2023年政策修订增补工作正在进行中,欢迎参与!
  • Moegirl.ICU:萌娘百科流亡社群 581077156(QQ),欢迎对萌娘百科运营感到失望的编辑者加入
  • Moegirl.ICU:账号认领正在试运行,有意者请参照账号认领流程

Module:Luaq

萌娘百科,万物皆可萌的百科全书!转载请标注来源页面的网页链接,并声明引自萌娘百科。内容不可商用。
跳转到导航 跳转到搜索
Template-info.svg 模块文档  [查看] [编辑] [历史] [刷新]

LUAQ是Lua Query的缩写,通过一系列查询函数让以Lua表(table)为主的数据源查询代码更加简洁。

使用配置

在模块代码中添加如下代码:

require("Module:Luaq")

之后便可以通过luaq使用各种查询函数。

使用

本章节将会介绍LUAQ的基本概念、查询函数的文档说明以及使用时必须或可选的注意事项。

若您想要了解查询函数的实现细节,或者希望修改结构、添加更多查询函数,请参阅#开发章节。

基本概念

查询对象

查询对象是由LUAQ的查询函数按照某种规范生成的特殊对象,它的本质是Lua表,但由于其内部的结构对于使用者来说是未知的,所以无法通过一般的手段获取它的内部结构。

实际上,使用者没有必要尝试去获取它的内部结构,若要获取它包含的内容,请参阅#查询展开章节。

延迟查询

延迟查询是LUAQ的重要特征之一,它表现为——当查询对象被生成时,查询对象并不会立即展开。唯有调用某些查询函数时,查询对象才会被计算,并返回查询结果。

在“查询对象被生成时”和“调用立即展开查询对象的函数”之间,改变作为数据源的Lua表内容将对最终查询结果会造成影响;当查询对象被展开后,无论数据源发生任何改变,都不会改变查询结果。

#查询函数章节中,会立即展开查询对象的函数将注有说明。

查询展开

查询展开是指将包含了一系列指令的查询对象转化为结果的过程。一共有两种方式进行展开。

enum:

enum(query)

全局函数,返回展开查询对象的迭代器。

函数返回三个值:

  1. 迭代器函数
  2. 查询对象本身
  3. 0

迭代器用在泛型for循环中。

luaq.query:

请参阅luaq.query

查询函数调用格式

为了使代码更加直观简洁,LUAQ在Lua函数调用语法糖的基础上支持了更简洁的写法。以下两种写法是等价的:

函数:

luaq.<查询函数名称>(查询对象[, 参数1[, 参数2[..., 参数n]]])

语法糖:

查询对象:<查询函数名称>([, 参数1[, 参数2[..., 参数n]]])

当您使用了语法糖调用形式,并且遇到了莫名其妙的“函数“...”的第1个参数类型错误(应为table,实为...)。"”报错,不妨检查一下是否将:错写成了.

查询函数

luaq.query

luaq.query(query)

展开一个查询对象

这个函数将立即展开查询对象,并将查询结果包装为一个Lua表返回。
参数:
返回:
一个Lua表,其数值类型的键即为查询结果每一项的位置索引。

luaq.asQuery

luaq.asQuery(t)

将一个Lua表包装为查询对象

当参数t已经是查询对象时,将返回其本身。
参数:
  • t:一个Lua表。
返回:
一个查询对象
若参数t为一个查询对象时,函数将会返回t自身。
否则将会返回一个包装了t查询对象
错误:
  1. 函数“asQuery”的第1个参数类型错误(应为table,实为...)。":当参数t的值不是一个Lua表的时候抛出此错误。
示例:
  • 代码:
<strong class="error"><span class="scribunto-error" id="mw-scribunto-error-7ed85f88">脚本错误:函数“main”不存在。</span></strong>
  • 结果:
<strong class="error"><span class="scribunto-error" id="mw-scribunto-error-7ed85f88">脚本错误:函数“main”不存在。</span></strong>

luaq.select

luaq.select(query, func)

对旧查询对象的每一个项进行指定的转换,并将结果形成新的查询对象。

参数:
  • query:一个查询对象,其每一个项将要被转换。
  • func:对query的每一个项进行的转换函数。转换函数将会接受到两个参数值:
    • 第1个参数值:query的当前项。
    • 第2个参数值:从开始到当前的索引。
返回:
一个查询对象。它由转换后的项组成。
错误:
  1. bad argument #2 to 'select' (table expected, got ...):当参数func的值不是一个函数的时候抛出此错误。
示例1:

在本示例中,转换函数返回当前项的值的类型。

  • 代码:
<strong class="error"><span class="scribunto-error" id="mw-scribunto-error-7ed85f88">脚本错误:函数“main”不存在。</span></strong>
  • 结果:
<strong class="error"><span class="scribunto-error" id="mw-scribunto-error-7ed85f88">脚本错误:函数“main”不存在。</span></strong>
示例2:

在本示例中,luaq.select函数判断当前索引的奇偶性。若索引为奇数,则返回key字段的值;若索引为偶数,则返回value字段的值。

  • 代码:
local t = { 5, 4, 3, str = "string" , 2, 1}
local q = luaq.asQuery(t)
    :select(
        function(pair, i)
            if math.fmod(i, 2) == 1 then return pair.key
            else return pair.value
            end
        end
    )
local r = q:query()

for key, value in pairs(t) do
    print("key = "..key.."\tvalue = "..value)
end

print()
print("查询结果:")
for i, v in ipairs(r) do
    print(v)
end
  • 结果:
key = 1         value = 5
key = 2         value = 4
key = 3         value = 3
key = 4         value = 2
key = 5         value = 1
key = str       value = string

查询结果:
1
4
3
2
5
string

luaq.where

luaq.where(query, func)

对旧查询对象的每一个项进行指定的筛选,并将符合条件的结果形成新的查询对象。

参数:
  • query:一个查询对象,其每一个项将要被筛选。
  • func:对query的每一个项进行检测的筛选函数。检测函数应返回truefalse,且将会接受到两个参数值:
    • 第1个参数值:query的当前项。
    • 第2个参数值:从开始到当前的索引。
返回:
一个查询对象。它由筛选后的项组成。
错误:
  1. bad argument #2 to 'where' (table expected, got ...):当参数func的值不是一个函数的时候抛出此错误。
示例:

本示例在luaq.select函数的示例1的基础上进行筛选。luaq.where函数的筛选机制为“项的值是字符串类型”或“项的值不小于3”。

  • 代码:
local t = { 5, 4, 3, str = "string" , 2, 1}
local q = luaq.asQuery(t)
    :select(
        function(pair)
            return type(pair.value)
        end
    )
    :where(
        function(e)
            return type(e) == "string" or e >= 3
        end
    )
local r = q:query()

for key, value in pairs(t) do
    print("key = "..key.."\tvalue = "..value)
end

print()
print("查询结果:")
for i, v in ipairs(r) do
    print(v)
end
  • 结果:
key = 1         value = 5
key = 2         value = 4
key = 3         value = 3
key = 4         value = 2
key = 5         value = 1
key = str       value = string

查询结果:
4
3
5
string

luaq.count

luaq.count(query)

获取查询结果中项的数量。

这个函数将立即展开查询对象。
参数:
  • query:一个查询对象。
返回:
查询结果中项的数量。
示例:

本示例同时演示了LUAQ的延迟查询。表中含有6对值键对,因此第一次luaq.count查询的结果为6。

删去表中的第二个元素后,已通过调用luaq.query展开查询的变量r,其循环遍历输出的内容不变,但第二次luaq.count查询的结果变为5。

  • 代码:
local t = { 5, 4, 3, str = "string" , 2, 1}
local q = luaq.asQuery(t)
local r = q:query()
for i, pair in ipairs(r) do
	print(pair.key.."\t"..pair.value)
end
print("count() = "..q:count())

print()
table.remove(t, 2) --删去表中的第二个元素
for i, pair in ipairs(r) do
	print(pair.key.."\t"..pair.value)
end
print("count() = "..q:count())
  • 结果:
1       5
2       4
3       3
4       2
5       1
str     string
count() = 6

1       5
2       4
3       3
4       2
5       1
str     string
count() = 5

luaq.any

luaq.all

luaq.distinct

luaq.groupBy

开发

本章节将会介绍LUAQ的实现细节、开发相关的文档说明等。

查询对象保留字段

查询对象本质是一个Lua表。为了判断一个Lua表是否为查询对象,同时为了实现LUAQ核心功能,该Lua表必须设置元表(metatable)并且遵守以下约束

  • __enum(必须)一个函数,返回查询对象的枚举器。
  • __reset(可选)一个函数,用于重置查询对象的状态。
  • __index(可选)一个函数,用于按数字索引获取对应的查询结果的项目。
  • __ipairs(可选)一个函数,用于重写_G.ipairs函数逻辑。
  • __pairs(可选)一个函数,用于重写_G.pairs函数逻辑。

除此之外,各个LUAQ查询函数生成的查询对象的元表也有各自的保留字段,请在开发中避免占用。

各查询函数的保留字段将分别说明。

枚举器

对每一个查询对象调用__getenumerator函数即可获得其枚举器。

枚举器是支持LUAQ延迟查询的基石,通过改变其内部的状态可以实现向前、向后查询等操作。

可以通过以下两种方式获取枚举器的对象:

  • 函数:

<查询对象>.__getenumerator(<查询对象>)

  • 语法糖:

<查询对象>:__getenumerator()

枚举器字段

枚举器是一个Lua表,为了正常工作,它必须具有以下字段:

  • current:这个字段的类型为函数,用以获取当前查询的项。
    调用:
    • 函数<枚举器对象>.current(self, query)
    • 语法糖<枚举器对象>:current(query)
    参数:
    self:即<枚举器对象>本身,用以支持语法糖调用。
    query:包含<枚举器对象>查询对象
    返回:
    当前查询的项。
  • moveLast:这个字段的类型为返回值为truefalse函数,用以将枚举器内部的状态向后回退一次。
    调用:
    • 函数<枚举器对象>.moveLast(self, query)
    • 语法糖<枚举器对象>:moveLast(query)
    参数:
    self:即<枚举器对象>本身,用以支持语法糖调用。
    query:包含<枚举器对象>查询对象
    返回:
    一个值,指示回退操作是否成功。
  • moveNext:这个字段的类型为返回值为truefalse函数,用以将枚举器内部的状态向前前进一次。
    调用:
    • 函数<枚举器对象>.moveNext(self, query)
    • 语法糖<枚举器对象>:moveNext(query)
    参数:
    self:即<枚举器对象>本身,用以支持语法糖调用。
    query:包含<枚举器对象>查询对象
    返回:
    一个值,指示前进操作是否成功。
  • saveState:这个字段的类型为函数,用以获取枚举器内部的当前状态。
    调用:
    • 函数<枚举器对象>.saveState(self, query)
    • 语法糖<枚举器对象>:saveState(query)
    参数:
    self:即<枚举器对象>本身,用以支持语法糖调用。
    query:包含<枚举器对象>查询对象
    返回:
    枚举器内部的当前状态。
  • resetState:这个字段的类型为函数,用以设置枚举器内部的当前状态。
    调用:
    • 函数<枚举器对象>.resetState(self, query, state)
    • 语法糖<枚举器对象>:resetState(query, state)
    参数:
    self:即<枚举器对象>本身,用以支持语法糖调用。
    query:包含<枚举器对象>查询对象
    state:要设置的枚举器内部的状态。

枚举器工作原理

  1. 获取查询对象query
  2. 通过query:__getenumerator()获取枚举器enumerator。除非特殊设计,一般的枚举器的初始状态为起点。
  3. 调用enumerator:moveNext(query)枚举器内部状态前进一次,若返回值为true,则继续下一步。
  4. 调用enumerator:current(query)获取当前的项current
  5. current进行后续处理。
示例:
local query = luaq.asQuery({ 5, 4, 3, 2, 1 })
local enumerator = query:__getenumerator()
while enumerator:moveNext(query) do
    local current = enumerator:current(query)
    print(current.key.."\t"..current.value)
end
结果:
1       5
2       4
3       3
4       2
5       1

查询函数实现细节

实现细节:linq.query

_G.luaq = {
    util = {}
}

function luaq.util.errBadArgType(funcName, paramIndex, expectedType, arg)
    error(mw.ustring.format("函数“%s”的第%d个参数类型错误(应为%s,实为%s)。", funcName, paramIndex, expectedType, type(arg)))
end

function luaq.util.errBadArgValue(funcName, paramIndex, expectedValue, arg, message, ...)
    local gotValue = type(arg)
    if gotValue == "number" or gotValue == "string" or gotValue == "boolean" then gotValue = mw.dumpObject(arg) end
    if type(message) == "string" then
        message = mw.ustring.format(message,expectedValue, arg, ...)
    else
        message = mw.ustring.format("(应为%s,实为%s)", expectedValue, mw.dumpObject(arg))
    end
    error(mw.ustring.format("函数“%s”的第%d个参数的值错误%s。", funcName, paramIndex, message))
end

function luaq.util.equal(l, r)
    -- 对键的每一个项目进行相等比较。
    local maxIndex = math.max(select("#", unpack(l)), select("#", unpack(r)))
    for _index = 1, maxIndex do
        if l[_index] ~= r[_index] then
            return false
        end
    end
    return true
end

function luaq.util.compare(l, r)
    -- 对键的每一个项目进行大小比较。
    local maxIndex = math.max(select("#", unpack(l)), select("#", unpack(r)))
    -- 越靠前的项目遇到不相等时,则两个键的大小关系等于这两个项目的大小关系。
    for _index = 1, maxIndex do
        local le, re = l[_index], r[_index]
        if le < re then return -1
        elseif le > re then return 1
        end
    end
    return 0 -- 所有项目均相等,则两个键相等。
end

local function isQuery(t)
    if type(t) ~= "table" then return false end

    local mt = getmetatable(t)
    return type(mt) == "table" and type(mt.__enum) == "function" and (mt.__reset == nil or type(mt.__reset) == "function")
end

-- 查询对象的默认索引元函数。(必须提供缓存元函数的实现。)
local function __index(query, k)
    if type(k) == "number" and k > 0 then
        local self = getmetatable(query)
        self:__cachetill(k) -- 计算查询结果到索引k的项并缓存。

        return self.__cache[k]
    end
end

-- 查询对象的默认枚举元函数。(必须提供索引元函数的实现。)
local function __enum(query, index)
    index = index + 1
    local current = query[index]
    if current then
        return index, current
    end
end

-- 查询对象的默认有序迭代元函数。
local function __ipairs(query)
    return getmetatable(query).__enum, query, 0
end

-- 查询对象的默认无序迭代元函数。
local __pairs = __ipairs

local function enext(query, index)
    local index, current = getmetatable(query).__enum(query, index)
    if current then
        return index, unpack(current)
    end
end
function _G.enum(query)
    if not isQuery(query) then luaq.util.errBadArgValue("enum", 1, "查询对象", t, "(不是%s)。") end

    return enext, query, 0
end

function _G.resetstate(query)
    if not isQuery(query) then luaq.util.errBadArgValue("enum", 1, "查询对象", t, "(不是%s)。") end

    local __reset = getmetatable(query).__reset -- 获取重置元函数。
    if __reset then
        __reset(query) -- 调用重置元函数。
    end
end

-- 将一个Lua表的所有值键对包装成查询对象。
function luaq.asQuery(t)
    if type(t) ~= "table" then luaq.util.errBadArgType("asQuery", 1, "table", t) end

    if isQuery(t) then return t end -- 已经是查询对象了,不再重复操作。

    local rtenum, rt, rtstate -- 内部表的枚举函数、固定值、以及初始状态。
    local mt = {
        __cache = {},
        __cachedone = false
    }
    mt.__index = __index
    mt.__cachetill = function(self, index)
        if self.__cachedone then return end -- 如果已缓存完毕则退出。
        if type(index) ~= "number" then luaq.util.errBadArgType("__cachetill", 2, "number", index) end
        if index <= 0 then luaq.util.errBadArgValue("__cachetill", 2, "正整数", index) end

        local c = self.__cache -- 获取缓存数组。
        if index <= #c then return end -- 如果指定索引小于已缓存项的数量,则直接退出。

        if rtenum == nil then
            rtenum, rt, rtstate = _G.pairs(t) -- 获取内部表的枚举函数、固定值、以及初始状态。
        end
        if type(rtenum) ~= "function" then luaq.util.errBadArgValue("asQuery", 1, nil, nil, "(全局pairs函数返回意外的值,找不到迭代函数)") end

        local state = c[#c] -- 当前起始状态为缓存数组的最末项。
        if state then
            state = state[1] -- 取键为起始状态。
        else
            state = rtstate -- 使用内部表提供的初始值为起始状态。
        end
        local k, v = state, nil -- (优化)
        while index > #c do
            k, v = rtenum(rt, k)
            if k == nil then break end

            table.insert(c, { k, v }) -- 向缓存数组中插入新项。
        end

        if k == nil then self.__cachedone = true end -- 仅当没有下一个键时设置缓存完毕标识符。
    end
    mt.__enum = __enum
    mt.__reset = function(q)
        local self = getmetatable(q)
        self.__cache = {}
        self.__cachedone = false

        rtenum, rt, rtstate = nil, nil, nil
    end
    mt.__ipairs = __ipairs
    mt.__pairs = __pairs

    local qResult = {}
    luaq.util.attachLuaq(qResult, mt)

    return qResult
end

-- 将一个Lua表的第一个不包含nil的序列包装成查询对象。
function luaq.iasQuery(t)
    if type(t) ~= "table" then luaq.util.errBadArgType("iasQuery", 1, "table", t) end

    if isQuery(t) then return t end -- 已经是查询对象了,不再重复操作。

    local rtenum, rt, rtstate -- 内部表的枚举函数、固定值、以及初始状态。
    local mt = {
        __cache = {
            states = {} -- 保存状态的数组。
        },
        __cachedone = false
    }
    mt.__index = __index
    mt.__cachetill = function(self, index)
        if self.__cachedone then return end -- 如果已缓存完毕则退出。
        if type(index) ~= "number" then luaq.util.errBadArgType("__cachetill", 2, "number", index) end
        if index <= 0 then luaq.util.errBadArgValue("__cachetill", 2, "正整数", index) end

        local c = self.__cache -- 获取缓存数组。
        if index <= #c then return end -- 如果指定索引小于已缓存项的数量,则直接退出。

        if rtenum == nil then
            rtenum, rt, rtstate = _G.ipairs(t) -- 获取内部表的枚举函数、固定值、以及初始状态。
        end
        if type(rtenum) ~= "function" then luaq.util.errBadArgValue("iasQuery", 1, nil, nil, "(全局ipairs函数返回意外的值,找不到迭代函数)") end

        local state, v
        if #c.states > 0 then
            state = c.states[#c.states] -- 当前起始状态为状态数组的最末项索引(或数组长度)。
        else
            state = rtstate -- 使用内部表提供的初始值为起始状态。
        end
        while index > #c do
            state, v = rtenum(rt, state)
            if v == nil then break end

            table.insert(c, { v }) -- 向缓存数组中插入新项。
            table.insert(c.states, state) -- 向状态数组中插入新项。
        end

        if v == nil then self.__cachedone = true end -- 仅当数组下一个项是nil时设置缓存完毕标识符。
    end
    mt.__enum = __enum
    mt.__reset = function(q)
        local self = getmetatable(q)
        self.__cache = {
            states = {}
        }
        self.__cachedone = false

        rtenum, rt, rtstate = nil, nil, nil
    end
    mt.__ipairs = __ipairs
    mt.__pairs = __pairs

    local qResult = {}
    luaq.util.attachLuaq(qResult, mt)

    return qResult
end

-- 将可变参数序列包装成查询对象。
function luaq.asQueryFrom(...)
    local rt = { ... }
    local count = select("#", unpack(rt)) -- 获取可变参数序列的长度。

    local mt = {
        __cache = {},
        __cachedone = false
    }
    mt.__index = __index
    mt.__cachetill = function(self, index)
        if self.__cachedone then return end -- 如果已缓存完毕则退出。
        if type(index) ~= "number" then luaq.util.errBadArgType("__cachetill", 2, "number", index) end
        if index <= 0 then luaq.util.errBadArgValue("__cachetill", 2, "正整数", index) end

        local c = self.__cache -- 获取缓存数组。
        if index <= #c then return end -- 如果指定索引小于已缓存项的数量,则直接退出。

        local state = #c -- 当前起始状态为缓存数组的最末项索引(或数组长度)。
        while index <= count and index > state do
            local v = rt[state + 1]
            table.insert(c, { v }) -- 向缓存数组中插入新项。
            state = state + 1
        end

        if state == count then self.__cachedone = true end -- 仅当缓存数组长度与可变参数序列长度一致时设置缓存完毕标识符。
    end
    mt.__enum = __enum
    mt.__reset = nil -- 常量可变参数序列不再变化,无重置必要。
    mt.__ipairs = __ipairs
    mt.__pairs = __pairs

    local qResult = {}
    luaq.util.attachLuaq(qResult, mt)

    return qResult
end

function luaq.select(query, func)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("select", 1, "查询对象", query, "(不是%s)。")
    end
    if type(func) ~= "function" then luaq.util.errBadArgType("select", 2, "function", func) end

    local iqenum, iq -- 内部查询对象的枚举元函数以及固定值。
    local mt = {
        __cache = {},
        __cachedone = false
    }
    mt.__index = __index
    mt.__cachetill = function(self, index)
        if self.__cachedone then return end -- 如果已缓存完毕则退出。
        if type(index) ~= "number" then luaq.util.errBadArgType("__cachetill", 2, "number", index) end
        if index <= 0 then luaq.util.errBadArgValue("__cachetill", 2, "正整数", index) end

        local c = self.__cache -- 获取缓存数组。
        if index <= #c then return end -- 如果指定索引小于已缓存项的数量,则直接退出。

        if iqenum == nil then
            iqenum, iq = getmetatable(query).__enum, query -- 获取内部查询对象的枚举元函数以及固定值。
        end

        local state, next = #c, nil -- 当前起始状态为缓存数组的最末项索引(或数组长度)。
        while index > #c do
            state, next = iqenum(iq, state)
            if next == nil then break end

            next = { func(state, unpack(next)) } -- 调用选择函数。
            table.insert(c, next) -- 向缓存数组中插入新项。
        end

        if next == nil then self.__cachedone = true end -- 仅当数组下一个项是nil时设置缓存完毕标识符。
    end
    mt.__enum = __enum
    mt.__reset = function(q)
        local __reset = getmetatable(query).__reset -- 获取重置元函数。
        if __reset then __reset(query) end -- 首先重置内部查询对象。

        local self = getmetatable(q)
        self.__cache = {}
        self.__cachedone = false

        iqenum, iq = nil, nil
    end
    mt.__ipairs = __ipairs
    mt.__pairs = __pairs

    local qResult = {}
    luaq.util.attachLuaq(qResult, mt)

    return qResult
end

function luaq.selectMany(query, func)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("selectMany", 1, "查询对象", t, "(不是%s)。")
    end
    if func ~= nil and type(func) ~= "function" then luaq.util.errBadArgType("selectMany", 2, "nil或function", func) end

    local iqenum, iq, iqstate -- 内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local tqenum, tq, tqstate -- 临时查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local mt = {
        __cache = {},
        __cachedone = false
    }
    mt.__index = __index
    mt.__cachetill = function(self, index)
        if self.__cachedone then return end -- 如果已缓存完毕则退出。
        if type(index) ~= "number" then luaq.util.errBadArgType("__cachetill", 2, "number", index) end
        if index <= 0 then luaq.util.errBadArgValue("__cachetill", 2, "正整数", index) end

        local c = self.__cache -- 获取缓存数组。
        if index <= #c then return end -- 如果指定索引小于已缓存项的数量,则直接退出。

        if iqenum == nil then
            iqenum, iq, iqstate = getmetatable(query).__enum, query, 0 -- 获取内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
            iqstate, tq = iqenum(iq, iqstate)
        end

        local next
        while index > #c do
            if tq == nil then break end

            if tqenum == nil then
                if func == nil then
                    tq = unpack(tq) -- 拆包,获取元组第一个项目,进行下一步处理。
                else
                    tq = { func(iqstate, unpack(tq)) }
                end
                if type(tq) == "table" then
                    if not isQuery(tq) then
                        tq = luaq.iasQuery(tq)
                    end
                else
                    error(mw.ustring.format("处理序列中的第%d项时发生错误(不是查询对象)。", iqstate))
                end
                tqenum, tqstate = getmetatable(tq).__enum, 0 -- 获取临时查询对象的枚举元函数以及迭代器的起始状态。
            end
            tqstate, next = tqenum(tq, tqstate)

            if next == nil then
                iqstate, tq = iqenum(iq, iqstate) -- 获取内部查询对象的枚举元函数以及迭代器的起始状态。
                tqenum, tqstate = nil, nil
            else
                table.insert(c, next) -- 向缓存数组中插入新项。
            end
        end

        if tq == nil then self.__cachedone = true end -- 仅当数组下一个项是nil时设置缓存完毕标识符。
    end
    mt.__enum = __enum
    mt.__reset = function(q)
        local __reset = getmetatable(query).__reset -- 获取重置元函数。
        if __reset then __reset(query) end -- 首先重置内部查询对象。

        local self = getmetatable(q)
        self.__cache = {}
        self.__cachedone = false

        iqenum, iq, iqstate = nil, nil, nil
        tqenum, tq, tqstate = nil, nil, nil
    end
    mt.__ipairs = __ipairs
    mt.__pairs = __pairs

    local qResult = {}
    luaq.util.attachLuaq(qResult, mt)

    return qResult
end

function luaq.selectYield(query, func)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("select", 1, "查询对象", query, "(不是%s)。")
    end
    if type(func) ~= "function" then luaq.util.errBadArgType("select", 2, "function", func) end

    local iqenum, iq, state -- 内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local mt = {
        __cache = {},
        __cachedone = false
    }
    local yield = function(...) table.insert(mt.__cache, { ... }) end -- 迭代器产出函数。
    mt.__index = __index
    mt.__cachetill = function(self, index)
        if self.__cachedone then return end -- 如果已缓存完毕则退出。
        if type(index) ~= "number" then luaq.util.errBadArgType("__cachetill", 2, "number", index) end
        if index <= 0 then luaq.util.errBadArgValue("__cachetill", 2, "正整数", index) end

        local c = self.__cache -- 获取缓存数组。
        if index <= #c then return end -- 如果指定索引小于已缓存项的数量,则直接退出。

        if iqenum == nil then
            iqenum, iq, state = getmetatable(query).__enum, query, 0 -- 获取内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
        end

        local next
        while index > #c do
            state, next = iqenum(iq, state)
            if next == nil then break end

            func(yield, state, unpack(next)) -- 调用迭代函数。
        end

        if next == nil then self.__cachedone = true end -- 仅当数组下一个项是nil时设置缓存完毕标识符。
    end
    mt.__enum = __enum
    mt.__reset = function(q)
        local __reset = getmetatable(query).__reset -- 获取重置元函数。
        if __reset then __reset(query) end -- 首先重置内部查询对象。

        local self = getmetatable(q)
        self.__cache = {}
        self.__cachedone = false

        iqenum, iq, state = nil, nil, nil
    end
    mt.__ipairs = __ipairs
    mt.__pairs = __pairs

    local qResult = {}
    luaq.util.attachLuaq(qResult, mt)

    return qResult
end

function luaq.where(query, func)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("where", 1, "查询对象", query, "(不是%s)。")
    end
    if type(func) ~= "function" then luaq.util.errBadArgType("where", 2, "function", func) end

    local iqenum, iq, state -- 内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local mt = {
        __cache = {},
        __cachedone = false
    }
    mt.__index = __index
    mt.__cachetill = function(self, index)
        if self.__cachedone then return end -- 如果已缓存完毕则退出。
        if type(index) ~= "number" then luaq.util.errBadArgType("__cachetill", 2, "number", index) end
        if index <= 0 then luaq.util.errBadArgValue("__cachetill", 2, "正整数", index) end

        local c = self.__cache -- 获取缓存数组。
        if index <= #c then return end -- 如果指定索引小于已缓存项的数量,则直接退出。

        if iqenum == nil then
            iqenum, iq, state = getmetatable(query).__enum, query, 0 -- 获取内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
        end

        local next = nil
        while index > #c do
            state, next = iqenum(iq, state)
            if next == nil then break end

            if func(state, unpack(next)) then -- 调用筛选函数。
                table.insert(c, { unpack(next) }) -- 向缓存数组中插入新项。
            end
        end

        if next == nil then self.__cachedone = true end -- 仅当数组下一个项是nil时设置缓存完毕标识符。
    end
    mt.__enum = __enum
    mt.__reset = function(q)
        local __reset = getmetatable(query).__reset
        if __reset then __reset(query) end -- 首先重置内部查询对象。

        local self = getmetatable(q)
        self.__cache = {}
        self.__cachedone = false

        iqenum, iq, state = nil, nil, nil
    end
    mt.__ipairs =__ipairs
    mt.__pairs = __pairs

    local qResult = {}
    luaq.util.attachLuaq(qResult, mt)

    return qResult
end

-- 创建一个空的查询对象。
function luaq.empty()
    local mt = {}
    mt.__enum = function(q, index) return nil end
    mt.__reset = nil
    mt.__ipairs = __ipairs
    mt.__pairs = __pairs

    local qResult = {}
    luaq.util.attachLuaq(qResult, mt)

    return qResult
end

-- 获取一个查询对象的结果的项个数。
function luaq.count(query)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("count", 1, "查询对象", t, "(不是%s)。")
    end

    local count = 0
    for _ in enum(query) do
        count = count + 1
    end

    return count
end

function luaq.any(query, func)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("any", 1, "查询对象", t, "(不是%s)。")
    end

    local qenum = getmetatable(query).__enum -- 获取枚举元函数。
    if type(func) == "nil" then
        local _, v = qenum(query, 0)
        return v ~= nil
    elseif type(func) ~= "function" then
        luaq.util.errBadArgType("any", 2, "function", func)
    end

    local i, v = qenum(query, 0)
    while v ~= nil do
        if func(unpack(v)) then return true end
        i, v = qenum(query, i)
    end
    return false
end

function luaq.all(query, func)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("all", 1, "查询对象", t, "(不是%s)。")
    end
    if type(func) ~= "function" then
        luaq.util.errBadArgType("all", 2, "function", func)
    end

    local qenum = getmetatable(query).__enum -- 获取枚举元函数。
    local i, v = qenum(query, 0)
    while v ~= nil do
        if not func(unpack(v)) then return false end
        i, v = qenum(query, i)
    end
    return true
end

function luaq.groupBy(query, keySelectFunc, entrySelectFunc, keyEqualityFunc)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("groupBy", 1, "查询对象", query, "(不是%s)。")
    end
    if type(keySelectFunc) ~= "function" then luaq.util.errBadArgType("groupBy", 2, "function", keySelectFunc) end
    if entrySelectFunc ~= nil and type(entrySelectFunc) ~= "function" then
        luaq.util.errBadArgType("groupBy", 3, "nil或function", entrySelectFunc)
    end
    if keyEqualityFunc ~= nil and type(keyEqualityFunc) ~= "function" then
        luaq.util.errBadArgType("groupBy", 4, "nil或function", keyEqualityFunc)
    end

    local iqenum, iq, state -- 内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local mapcache = { -- 缓存所有项到键数组索引的映射。
        keys = {}, -- 储存所有键的数组。
        cachedone = false,
        cachenext = function(self)
            if self.cachedone then return end -- 如果已缓存完毕则退出。

            if iqenum == nil then
                iqenum, iq, state = getmetatable(query).__enum, query, 0 -- 获取内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
            end

            local next = nil
            state, next = iqenum(iq, state)
            if next == nil then
                self.cachedone = true -- 仅当数组下一个项是nil时设置缓存完毕标识符。
                return
            end

            local knext = { keySelectFunc(state, unpack(next)) } -- 调用键选择函数。

            -- 遍历键数组中所有已有键,与新键进行相等比较判断是否相等。
            local hasKey = false
            for _keyindex, _key in ipairs(self.keys) do
                local keyTest -- 键相等检查
                if keyEqualityFunc == nil then
                    keyTest = luaq.util.equal(_key, knext)
                else
                    keyTest = keyEqualityFunc(_key, knext)
                end
                if keyTest then -- 找到已有的相同的键,则将当前项归组至这个键。
                    hasKey = true
                    table.insert(self, { _keyindex, next }) -- 缓存数组中保存指向键数组的索引+项。
                    break
                end
            end
            if not hasKey then -- 未找到已有的相同的键,则创建新键以归组当前项。
                table.insert(self.keys, knext) -- 向键数组插入一个不同的键。
                table.insert(self, { #self.keys, next }) -- 向缓存数组插入指向键数组末尾的索引+项。
            end
        end,
        reset = function(self)
            local __reset = getmetatable(query).__reset -- 获取重置元函数。
            if __reset then __reset(query) end -- 首先重置内部查询对象。

            self.keys = {} -- 重置键数组
            self.cachedone = false -- 重置缓存完毕标识符。
            local length = #self
            for i = 1, length do self[i] = nil end -- 清空映射缓存。

            iqenum, iq, state = nil, nil, nil
        end
    }

    local gmt = {
        __cache = {},
        __cachedone = false
    }
    gmt.__index = __index
    gmt.__cachetill = function(gself, gindex)
        if gself.__cachedone then return end -- 如果已缓存完毕则退出。
        if type(gindex) ~= "number" then luaq.util.errBadArgType("__cachetill", 2, "number", gindex) end
        if gindex <= 0 then luaq.util.errBadArgValue("__cachetill", 2, "正整数", gindex) end

        local gc = gself.__cache -- 获取缓存数组。
        if gindex <= #gc then return end -- 如果指定索引小于已缓存项的数量,则直接退出。

        while gindex > #gc do
            local nextKeyIndex = #gc + 1 -- 获取下一个键的索引。
            local nextKey = mapcache.keys[nextKeyIndex] -- 获取下一个键。
            while nextKey == nil and not mapcache.cachedone do -- 获取键时映射缓存未完成。
                -- 重复向后缓存一个项并检查是否得到下一个键。
                mapcache:cachenext()
                nextKey = mapcache.keys[nextKeyIndex]
            end
            if nextKey == nil then
                gself.__cachedone = true -- 映射缓存完毕时仍未找到下一个键,仅当此时设置缓存完毕标识符。
                break
            end

            local nextEntryIndex = 1 -- 获取下一个项的索引。
            local emt= {
                __cache = {},
                __cachedone = false
            }
            emt.__index = __index
            emt.__cachetill = function(eself, eindex)
                if eself.__cachedone then return end -- 如果已缓存完毕则退出。
                if type(eindex) ~= "number" then luaq.util.errBadArgType("__cachetill", 2, "number", eindex) end
                if eindex <= 0 then luaq.util.errBadArgValue("__cachetill", 2, "正整数", eindex) end

                local ec = eself.__cache -- 获取缓存数组。
                if eindex <= #ec then return end -- 如果指定索引小于已缓存项的数量,则直接退出。

                while eindex > #ec do
                    local nextEntry = mapcache[nextEntryIndex] -- 获取下一个项。
                    while (nextEntry == nil or nextEntry[1] ~= nextKeyIndex) do -- 获得的下个项不符合条件。
                        -- 重复向后缓存一个项并检查是否得到下一个符合条件的项。
                        if nextEntry == nil then -- 若当前索引位置未缓存,则缓存一个位置。
                            if mapcache.cachedone then break end -- 映射缓存已完毕。
                            mapcache:cachenext()
                        else -- 若当前索引位置的项不符合条件,则尝试下一个索引位置。
                            nextEntryIndex = nextEntryIndex + 1
                        end
                        nextEntry = mapcache[nextEntryIndex]
                    end
                    if nextEntry == nil then
                        eself.__cachedone = true -- 映射缓存完毕时仍未找到下一个项,仅当此时设置缓存完毕标识符。
                        break
                    end

                    local newEntry
                    if entrySelectFunc == nil then
                        newEntry = { nextKey, unpack(nextEntry[2]) }
                    else
                        newEntry = { nextKey, entrySelectFunc(eindex, mapcache.keys[nextKeyIndex], unpack(nextEntry[2])) } -- 调用项选择函数。
                    end
                    table.insert(ec, newEntry) -- 向缓存数组中插入新项。

                    nextEntryIndex = nextEntryIndex + 1
                end
            end
            emt.__enum = __enum
            emt.__reset = function(q)
                -- 项查询对象的重置将不改变分组结果,仅重新获取项选择函数的返回值。
                local self = getmetatable(q)
                self.__cache = {}
                self.__cachedone = false

                nextEntryIndex = 1
            end
            emt.__ipairs = __ipairs
            emt.__pairs = __pairs

            local eqResult = {}
            luaq.util.attachLuaq(eqResult, emt)

            -- 将项查询对象添加入缓存。
            table.insert(gc, { nextKey, eqResult })
        end
    end
    gmt.__enum = __enum
    gmt.__reset = function(q)
        mapcache:reset() -- 首先重置映射缓存。

        local self = getmetatable(q)
        self.__cache = {}
        self.__cachedone = false
    end
    gmt.__ipairs = __ipairs
    gmt.__pairs = __pairs

    local gqResult = {}
    luaq.util.attachLuaq(gqResult, gmt)

    return gqResult
end

local function isSort(sort) return type(sort) == "table" and type(sort.start) == "function" end
local function isOrderedQuery(t)
    return isQuery(t) and type(getmetatable(t).__group) == "function"
end
-- 获取默认排序器。
local function getDefaultSort(stages)
    return {
        start = function(self, info, desc, ...)
            -- 冒泡排序。
            local count = info.length(...)
            for i = 1, count do
                local swaped = false
                for j = 1, count - i do
                    if (info.compare(j, j + 1, ...) < 0) == desc then
                        swaped = info.swap(j, j + 1, ...) or swaped
                    end
                end
                if not swaped then break end
            end
        end
    }
end
function luaq.orderBy(query, func, comp, desc, sort)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("orderBy", 1, "查询对象", t, "(不是%s)。")
    end
    if func ~= nil and type(func) ~= "function" then luaq.util.errBadArgType("orderBy", 2, "function", func) end
    if comp ~= nil and type(comp) ~= "function" then luaq.util.errBadArgType("orderBy", 3, "nil或function", comp) end
    if desc == nil then desc = false
    elseif type(desc) ~= "boolean" then luaq.util.errBadArgType("orderBy", 4, "nil或boolean", desc) end
    if sort == nil then sort = getDefaultSort()
    elseif not isSort(sort) then luaq.util.errBadArgValue("orderBy", 5, "排序器", t, "(不是%s)。")
    end

    local iqenum, iq, state -- 内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local sortcache = {} -- 缓存排序内容等信息。
    sortcache.cachedone = false -- 缓存完毕标识符。
    sortcache.cacheall = function(self)
        if self.cachedone then return end -- 如果已缓存完毕则退出。

        if iqenum == nil then
            iqenum, iq, state = getmetatable(query).__enum, query, 0 -- 获取内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
        end

        local next = nil
        while true do
            state, next = iqenum(iq, state)
            if next == nil then break end -- 仅当数组下一个项是nil时循环终止。

            local pair = {} -- 排序键值对。
            if func == nil then
                pair = { next } -- 不做排序键选择,即将自身作为排序键。
            else
                pair = { { func(state, unpack(next)) }, next } -- 调用排序键选择函数。
            end
            -- 遍历缓存中所有已有项组,与下一项进行相等比较判断是否相等。
            local isEven = false
            for _, _group in ipairs(self) do
                local current = _group[1][1] -- 从项组中获取当前要比较的项。
                local evenTest -- 项相等检查
                if comp == nil then
                    evenTest = luaq.util.equal(current, pair[1])
                else
                    evenTest = comp(current, pair[1]) == 0
                end
                if evenTest then -- 找到已有的相同的项组,则将当前项归组至这个组。
                    isEven = true
                    table.insert(_group, pair)
                    break
                end
            end
            if not isEven then -- 未找到已有的相同的项组,则创建新组以归组当前项。
                table.insert(self, { pair })
            end
        end

        self.cachedone = true -- 设置缓存完毕标识符
    end
    sortcache.length = function() return #sortcache end
    sortcache.entryat = function(index)
        if type(index) ~= "number" then luaq.util.errBadArgType("entryat", 1, "number", index) end
        if index <= 0 then luaq.util.errBadArgValue("entryat", 1, "正整数", index) end

        local group = sortcache[index] -- 获取等值组。
        if group == nil then return nil
        else return group[1][1] -- 等值组的首项的选择键。
        end
    end
    sortcache.compare = function(index1, index2)
        if type(index1) ~= "number" then luaq.util.errBadArgType("compare", 1, "number", index1) end
        if index1 <= 0 then luaq.util.errBadArgValue("compare", 1, "正整数", index1) end
        if type(index2) ~= "number" then luaq.util.errBadArgType("compare", 2, "number", index2) end
        if index2 <= 0 then luaq.util.errBadArgValue("compare", 2, "正整数", index2) end

        local temp1, temp2 = sortcache[index1], sortcache[index2]
        if temp1 == nil and temp2 == nil then return 0 -- 两个索引均超出范围。
        elseif temp1 == nil then return -1 -- 第一个索引均超出范围。
        elseif temp2 == nil then return 1 -- 第二个索引均超出范围。
        else
            temp1, temp2 = temp1[1][1], temp2[1][1] -- 等值组的首项的选择键。
            if comp == nil then
                return luaq.util.compare(temp1, temp2)
            else
                return comp(temp1, temp2)
            end
        end
    end
    sortcache.swap = function(index1, index2)
        if type(index1) ~= "number" then luaq.util.errBadArgType("swap", 1, "number", index1) end
        if index1 <= 0 then luaq.util.errBadArgValue("swap", 1, "正整数", index1) end
        if type(index2) ~= "number" then luaq.util.errBadArgType("swap", 2, "number", index2) end
        if index2 <= 0 then luaq.util.errBadArgValue("swap", 2, "正整数", index2) end

        local temp1, temp2 = sortcache[index1], sortcache[index2]
        if temp1 == nil or temp2 == nil then return false end -- 其中任何一项索引超出范围则返回不成功。
        sortcache[index1], sortcache[index2] = temp2, temp1
        return true -- 交换操作成功。
    end
    sortcache.setall = function(indexes)
        if type(indexes) ~= "table" then luaq.util.errBadArgType("setall", 1, "table", indexes) end

        local length = #sortcache
        for i = 1, length do indexes[i] = sortcache[indexes[i]] end
        for i = 1, length do sortcache[i] = indexes[i] end
    end
    sortcache.sortdone = false -- 排序完毕标识符。
    sortcache.sort = function(self)
        if self.sortdone then return end

        self:cacheall() -- 缓存所有项。
        assert(self.cachedone, "排序缓存未缓存完毕,无法进行排序。") -- 设置断言捕捉潜在的逻辑错误。排序操作必须在缓存完毕的基础上进行,否则将会产生无法预料的后果。

        sort:start(self, desc) -- 调用排序器。
        self.sortdone = true
    end
    sortcache.reset = function(self)
        local __reset = getmetatable(query).__reset -- 获取重置元函数。
        if __reset then __reset(query) end -- 首先重置内部查询对象。

        self.cachedone = false -- 重置缓存完毕标识符。
        self.sortdone = false -- 重置排序完毕标识符。
        local length = #self
        for i = 1, length do self[i] = nil end -- 清空排序缓存。

        iqenum, iq, state = nil, nil, 0
    end

    local mt = {
        __cache = {},
        __cachedone = false
    }
    mt.__index = __index
    mt.__cachetill = function(self, index)
        if self.__cachedone then return end -- 如果已缓存完毕则退出。
        if type(index) ~= "number" then luaq.util.errBadArgType("__cachetill", 2, "number", index) end
        if index <= 0 then luaq.util.errBadArgValue("__cachetill", 2, "正整数", index) end

        local c = self.__cache -- 获取缓存数组。
        if index <= #c then return end -- 如果指定索引小于已缓存项的数量,则直接退出。

        sortcache:sort() -- 排序所有项。
        assert(sortcache.sortdone, "排序缓存未排序完毕,无法进行结果缓存。") -- 设置断言捕捉潜在的逻辑错误。结果缓存操作必须在排序完毕的基础上进行,否则将会产生无法预料的后果。

        -- 缓存所有结果。
        for _, group in ipairs(sortcache) do
            for _, entry in ipairs(group) do
                table.insert(c, entry[2] or entry[1])
            end
        end
        self.__cachedone = true -- 设置缓存完毕标识符。
    end
    mt.__group = function(q, index)
        sortcache:sort() -- 排序所有项。
        assert(sortcache.sortdone, "排序缓存未排序完毕,无法进行排序组枚举。") -- 设置断言捕捉潜在的逻辑错误。排序组枚举操作必须在排序完毕的基础上进行,否则将会产生无法预料的后果。

        index = index + 1
        local current = sortcache[index]
        if current then
            local group = {}
            for _, current in ipairs(current) do
                table.insert(group, current[2] or current[1])
            end
            assert(#group > 0, "空的等值组。") -- 不应出现空的等值组。
            return index, group
        end
    end
    mt.__enum = __enum
    mt.__reset = function(q)
        sortcache:reset() -- 首先重置排序缓存。

        local self = getmetatable(q)
        self.__cache = {}
        self.__cachedone = false
    end
    mt.__ipairs = __ipairs
    mt.__pairs = __pairs

    local qResult = {}
    luaq.util.attachLuaq(qResult, mt)

    return qResult
end

function luaq.thenBy(query, func, comp, desc, sort)
    if not isOrderedQuery(query) then
        luaq.util.errBadArgValue("thenBy", 1, "有序查询对象", t, "(不是%s)。")
    end
    if func ~= nil and type(func) ~= "function" then luaq.util.errBadArgType("thenBy", 2, "function", func) end
    if comp ~= nil and type(comp) ~= "function" then luaq.util.errBadArgType("thenBy", 3, "nil或function", comp) end
    if desc == nil then desc = false
    elseif type(desc) ~= "boolean" then luaq.util.errBadArgType("thenBy", 4, "nil或boolean", desc) end
    if sort == nil then sort = getDefaultSort()
    elseif not isSort(sort) then luaq.util.errBadArgValue("thenBy", 5, "排序器", t, "(不是%s)。")
    end

    local iqgroup, iq, state -- 内部查询对象的排序组元函数、固定值以及迭代器的起始状态。
    local totalState = 0 -- 整体状态。
    local sortcache = {} -- 缓存排序内容等信息。
    sortcache.cachedone = false
    sortcache.cachenext = function(self)
        if self.cachedone then return false end -- 如果已缓存完毕则退出。

        if iqgroup == nil then
            iqgroup, iq, state = getmetatable(query).__group, query, 0 -- 获取内部查询对象的排序组元函数、固定值以及迭代器的起始状态。
        end

        local nextStage = nil
        state, nextStage = iqgroup(iq, state)
        if nextStage == nil then
            self.cachedone = true -- 仅当排序组下一个项是nil时设置缓存完毕标识符。
            return false
        end

        local stage = {} -- 新建高阶排序阶。
        for _, next in ipairs(nextStage) do
            local pair = {} -- 排序键值对。
            if func == nil then
                pair = { next } -- 不做排序键选择,即将自身作为排序键。
            else
                pair = { { func(totalState + state, unpack(next)) }, next } -- 调用排序键选择函数。
            end
            -- 遍历新排序阶中所有已有项组,与下一项进行相等比较判断是否相等。
            local isEven = false
            for _, _group in ipairs(stage) do
                local current = _group[1][1] -- 从项组中获取当前要比较的项。
                local evenTest -- 项相等检查
                if comp == nil then
                    evenTest = luaq.util.equal(current, pair[1])
                else
                    evenTest = comp(current, pair[1]) == 0
                end
                if evenTest then -- 找到已有的相同的项组,则将当前项归组至这个组。
                    isEven = true
                    table.insert(_group, pair)
                    break
                end
            end
            if not isEven then -- 未找到已有的相同的项组,则创建新组以归组当前项。
                table.insert(stage, { pair })
            end
        end
        table.insert(self, stage) -- 向排序缓存中添加新排序阶。

        return true
    end
    sortcache.length = function(stage)
        if type(stage) == "number" then
            local s = sortcache[stage]
            if s == nil then return nil -- 索引超出范围。
            else return #s -- 返回当前排序阶的长度。
            end
        else -- 返回总长度。
            local len = 0
            for _, s in sortcache do
                len = len + #s
            end
            return len
        end
    end
    sortcache.entryat = function(index, stage)
        if type(index) ~= "number" then luaq.util.errBadArgType("entryat", 1, "number", index) end
        if index <= 0 then luaq.util.errBadArgValue("entryat", 1, "正整数", index) end
        if type(stage) ~= "number" then luaq.util.errBadArgType("entryat", 2, "number", stage) end
        if stage <= 0 then luaq.util.errBadArgValue("entryat", 2, "正整数", stage) end

        stage = sortcache[stage] -- 获取排序阶。
        if stage == nil then return nil end -- 索引超出范围。
        local group = stage[index] -- 获取等值组。
        if group == nil then return nil
        else return group[1][1] -- 等值组的首项的选择键。
        end
    end
    sortcache.compare = function(index1, index2, stage)
        if type(index1) ~= "number" then luaq.util.errBadArgType("compare", 1, "number", index1) end
        if index1 <= 0 then luaq.util.errBadArgValue("compare", 1, "正整数", index1) end
        if type(index2) ~= "number" then luaq.util.errBadArgType("compare", 2, "number", index2) end
        if index2 <= 0 then luaq.util.errBadArgValue("compare", 2, "正整数", index2) end
        if type(stage) ~= "number" then luaq.util.errBadArgType("compare", 3, "number", stage) end
        if stage <= 0 then luaq.util.errBadArgValue("compare", 3, "正整数", stage) end

        stage = sortcache[stage] -- 获取排序阶。
        if stage == nil then return 0 end -- 索引超出范围。
        local temp1, temp2 = stage[index1], stage[index2]
        if temp1 == nil and temp2 == nil then return 0 -- 两个索引均超出范围。
        elseif temp1 == nil then return -1 -- 第一个索引均超出范围。
        elseif temp2 == nil then return 1 -- 第二个索引均超出范围。
        else
            temp1, temp2 = temp1[1][1], temp2[1][1] -- 等值组的首项的选择键。
            if comp == nil then
                return luaq.util.compare(temp1, temp2)
            else
                return comp(temp1, temp2)
            end
        end
    end
    sortcache.swap = function(index1, index2, stage)
        if type(index1) ~= "number" then luaq.util.errBadArgType("swap", 1, "number", index1) end
        if index1 <= 0 then luaq.util.errBadArgValue("swap", 1, "正整数", index1) end
        if type(index2) ~= "number" then luaq.util.errBadArgType("swap", 2, "number", index2) end
        if index2 <= 0 then luaq.util.errBadArgValue("swap", 2, "正整数", index2) end
        if type(stage) ~= "number" then luaq.util.errBadArgType("swap", 3, "number", stage) end
        if stage <= 0 then luaq.util.errBadArgValue("swap", 3, "正整数", stage) end

        stage = sortcache[stage] -- 获取排序阶。
        if stage == nil then return false end -- 索引超出范围。
        local temp1, temp2 = stage[index1], stage[index2]
        if temp1 == nil or temp2 == nil then return false end -- 其中任何一项索引超出范围则返回不成功。
        stage[index1], stage[index2] = temp2, temp1
        return true -- 交换操作成功。
    end
    sortcache.setall = function(indexes, stage)
        if type(indexes) ~= "table" then luaq.util.errBadArgType("setall", 1, "table", indexes) end

        stage = sortcache[stage] -- 获取排序阶。
        if stage == nil then return end -- 索引超出范围。
        local length = #stage
        for i = 1, length do indexes[i] = stage[indexes[i]] end
        for i = 1, length do stage[i] = indexes[i] end
    end
    sortcache.sortdone = false
    sortcache.sortnext = function(self)
        if self.sortdone then return false end

        local hasNext = self:cachenext() -- 缓存下一阶。
        if not hasNext then
            self.sortdone = true
            return false
        end

        local stage = #self -- 获取下一阶的索引。
        sort:start(self, desc, stage)

        return true
    end
    sortcache.reset = function(self)
        local __reset = getmetatable(query).__reset -- 获取重置元函数。
        if __reset then __reset(query) end -- 首先重置内部查询对象。

        self.cachedone = false -- 重置缓存完毕标识符。
        self.sortdone = false -- 重置排序完毕标识符。
        local length = #self
        for i = 1, length do self[i] = nil end -- 清空映射缓存。

        iqgroup, iq, state = nil, nil, 0
    end

    local mt = {
        __cache = {},
        __cachedone = false
    }
    mt.__index = __index
    mt.__cachetill = function(self, index)
        if self.__cachedone then return end -- 如果已缓存完毕则退出。
        if type(index) ~= "number" then luaq.util.errBadArgType("__cachetill", 2, "number", index) end
        if index <= 0 then luaq.util.errBadArgValue("__cachetill", 2, "正整数", index) end

        local c = self.__cache -- 获取缓存数组。
        if index <= #c then return end -- 如果指定索引小于已缓存项的数量,则直接退出。

        while index > #c and not sortcache.sortdone do
            if not sortcache:sortnext() then break end -- 排序下一阶。
            local stage = sortcache[#sortcache] -- 获取下一阶。

            -- 缓存下一阶的所有结果。
            for _, group in ipairs(stage) do
                for _, entry in ipairs(group) do
                    table.insert(c, entry[2] or entry[1])
                end
            end
        end
        if sortcache.sortdone then self.__cachedone = true end -- 仅当排序缓存的所有阶均排序完毕时设置缓存完毕标识符。
    end
    mt.__group = function(q, index)
        index = index + 1
        local current = nil

        local offset, stage = 0, 1
        while true do
            local s = sortcache[stage]
            if s == nil then
                -- 排序下一阶。
                if not sortcache:sortnext() then break end
                s = sortcache[stage]
                if s == nil then break end
            end

            if index <= offset + #s then
                current = s[index - offset]
                break
            end

            offset = offset + #s
            stage = stage + 1
        end

        if current then
            local group = {}
            for _, current in ipairs(current) do
                table.insert(group, current[2] or current[1])
            end
            assert(#group > 0, "空的等值组。") -- 不应出现空的等值组。
            return index, group
        end
    end
    mt.__enum = __enum
    mt.__reset = function(q)
        sortcache:reset() -- 首先重置排序缓存。

        local self = getmetatable(q)
        self.__cache = {}
        self.__cachedone = false
    end
    mt.__ipairs = __ipairs
    mt.__pairs = __pairs

    local qResult = {}
    luaq.util.attachLuaq(qResult, mt)

    return qResult
end

function luaq.distinct(query, func)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("distinct", 1, "查询对象", query, "(不是%s)。")
    end
    if func ~= nil and type(func) ~= "function" then luaq.util.errBadArgType("distinct", 2, "nil或function", func) end

    local iqenum, iq, state -- 内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local mt = {
        __cache = {},
        __cachedone = false
    }
    mt.__index = __index
    mt.__cachetill = function(self, index)
        if self.__cachedone then return end -- 如果已缓存完毕则退出。
        if type(index) ~= "number" then luaq.util.errBadArgType("__cachetill", 2, "number", index) end
        if index <= 0 then luaq.util.errBadArgValue("__cachetill", 2, "正整数", index) end

        local c = self.__cache -- 获取缓存数组。
        if index <= #c then return end -- 如果指定索引小于已缓存项的数量,则直接退出。

        if iqenum == nil then
            iqenum, iq, state = getmetatable(query).__enum, query, 0 -- 获取内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
        end

        local next = nil
        while index > #c do
            state, next = iqenum(iq, state)
            if next == nil then break end

            local isEven
            for _, current in ipairs(c) do
                if func then
                    local evenTest = func(current, next) -- 调用筛选函数。
                    isEven = evenTest == true or evenTest == 0
                else
                    isEven = luaq.util.equal(current, next)
                end
                if isEven then break end
            end
            if not isEven then
                table.insert(c, { unpack(next) }) -- 向缓存数组中插入新项。
            end
        end

        if next == nil then self.__cachedone = true end -- 仅当数组下一个项是nil时设置缓存完毕标识符。
    end
    mt.__enum = __enum
    mt.__reset = function(q)
        local __reset = getmetatable(query).__reset
        if __reset then __reset(query) end -- 首先重置内部查询对象。

        local self = getmetatable(q)
        self.__cache = {}
        self.__cachedone = false

        iqenum, iq, state = nil, nil, nil
    end
    mt.__ipairs =__ipairs
    mt.__pairs = __pairs

    local qResult = {}
    luaq.util.attachLuaq(qResult, mt)

    return qResult
end

function luaq.concat(query, other)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("concat", 1, "查询对象", query, "(不是%s)。")
    end
    if type(other) == "table" then
        if not isQuery(other) then
            other = luaq.iasQuery(other)
        end
    else
        luaq.util.errBadArgValue("concat", 2, "查询对象", other, "(不是%s)。")
    end

    local iqenum1, iqenum2 -- 两个查询对象的枚举元函数。
    local iqenum, iq, state -- 内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local mt = {
        __cache = {},
        __cachedone = false
    }
    mt.__index = __index
    mt.__cachetill = function(self, index)
        if self.__cachedone then return end -- 如果已缓存完毕则退出。
        if type(index) ~= "number" then luaq.util.errBadArgType("__cachetill", 2, "number", index) end
        if index <= 0 then luaq.util.errBadArgValue("__cachetill", 2, "正整数", index) end

        local c = self.__cache -- 获取缓存数组。
        if index <= #c then return end -- 如果指定索引小于已缓存项的数量,则直接退出。

        iqenum1 = iqenum1 or getmetatable(query).__enum
        iqenum2 = iqenum2 or getmetatable(other).__enum
        if iqenum == nil then
            iqenum, iq, state = iqenum1, query, 0 -- 获取第一个内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
        end

        local next
        while index > #c do
            state, next = iqenum(iq, state)
            local continue = false
            if next == nil then
                if iqenum == iqenum2 then break
                else
                    iqenum, iq, state = iqenum2, other, 0 -- 获取第二个内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
                    continue = true
                end
            end

            if not continue then
                table.insert(c, { unpack(next) }) -- 向缓存数组中插入新项。
            end
        end

        if next == nil then self.__cachedone = true end -- 仅当数组下一个项是nil时设置缓存完毕标识符。
    end
    mt.__enum = __enum
    mt.__reset = function(q)
        local __reset = getmetatable(query).__reset -- 获取第一个内部查询对象的重置元函数。
        if __reset then __reset(query) end -- 首先重置内部查询对象。
        __reset = getmetatable(other).__reset -- 获取第二个内部查询对象的重置元函数。
        if __reset then __reset(other) end -- 首先重置内部查询对象。

        local self = getmetatable(q)
        self.__cache = {}
        self.__cachedone = false

        iqenum, iq, state = nil, nil, nil
    end
    mt.__ipairs = __ipairs
    mt.__pairs = __pairs

    local qResult = {}
    luaq.util.attachLuaq(qResult, mt)

    return qResult
end

function luaq.append(query, ...)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("append", 1, "查询对象", query, "(不是%s)。")
    end
    if type(func) ~= "function" then luaq.util.errBadArgType("append", 2, "function", func) end

    local iqenum, iq, state -- 内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local extra = { ... } -- 要追加的项。
    local mt = {
        __cache = {},
        __cachedone = false
    }
    mt.__index = __index
    mt.__cachetill = function(self, index)
        if self.__cachedone then return end -- 如果已缓存完毕则退出。
        if type(index) ~= "number" then luaq.util.errBadArgType("__cachetill", 2, "number", index) end
        if index <= 0 then luaq.util.errBadArgValue("__cachetill", 2, "正整数", index) end

        local c = self.__cache -- 获取缓存数组。
        if index <= #c then return end -- 如果指定索引小于已缓存项的数量,则直接退出。

        if iqenum == nil then
            iqenum, iq, state = getmetatable(query).__enum, query, 0 -- 获取内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
        end

        local next
        while index > #c do
            state, next = iqenum(iq, state)
            if next == nil then break end

            table.insert(c, { unpack(next) }) -- 向缓存数组中插入新项。
        end

        if next == nil then -- 当数组下一个项是nil时。
            table.insert(c, extra) -- 向缓存数组中插入追加项。
            self.__cachedone = true -- 设置缓存完毕标识符
        end
    end
    mt.__enum = __enum
    mt.__reset = function(q)
        local __reset = getmetatable(query).__reset -- 获取重置元函数。
        if __reset then __reset(query) end -- 首先重置内部查询对象。

        local self = getmetatable(q)
        self.__cache = {}
        self.__cachedone = false

        iqenum, iq, state = nil, nil, nil
    end
    mt.__ipairs = __ipairs
    mt.__pairs = __pairs

    local qResult = {}
    luaq.util.attachLuaq(qResult, mt)

    return qResult
end

function luaq.prepend(query, ...)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("prepend", 1, "查询对象", query, "(不是%s)。")
    end
    if type(func) ~= "function" then luaq.util.errBadArgType("prepend", 2, "function", func) end

    local iqenum, iq, state -- 内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local extra = { ... } -- 要追加的项。
    local mt = {
        __cache = {},
        __cachedone = false
    }
    mt.__index = __index
    mt.__cachetill = function(self, index)
        if self.__cachedone then return end -- 如果已缓存完毕则退出。
        if type(index) ~= "number" then luaq.util.errBadArgType("__cachetill", 2, "number", index) end
        if index <= 0 then luaq.util.errBadArgValue("__cachetill", 2, "正整数", index) end

        local c = self.__cache -- 获取缓存数组。
        if index <= #c then return end -- 如果指定索引小于已缓存项的数量,则直接退出。

        if iqenum == nil then
            iqenum, iq, state = getmetatable(query).__enum, query, 0 -- 获取内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
            table.insert(c, extra) -- 向缓存数组中插入追加项。
        end

        local next
        while index > #c do
            state, next = iqenum(iq, state)
            if next == nil then break end

            table.insert(c, { unpack(next) }) -- 向缓存数组中插入新项。
        end

        if next == nil then self.__cachedone = true end -- 仅当数组下一个项是nil时设置缓存完毕标识符。
    end
    mt.__enum = __enum
    mt.__reset = function(q)
        local __reset = getmetatable(query).__reset -- 获取重置元函数。
        if __reset then __reset(query) end -- 首先重置内部查询对象。

        local self = getmetatable(q)
        self.__cache = {}
        self.__cachedone = false

        iqenum, iq, state = nil, nil, nil
    end
    mt.__ipairs = __ipairs
    mt.__pairs = __pairs

    local qResult = {}
    luaq.util.attachLuaq(qResult, mt)

    return qResult
end

function luaq.reverse(query)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("reverse", 1, "查询对象", query, "(不是%s)。")
    end

    local iqenum, iq, state -- 内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local mt = {
        __cache = {},
        __cachedone = false
    }
    mt.__index = function(q, k)
        if type(k) == "number" and k > 0 then
            local self = getmetatable(q)
            self:__cacheall() -- 计算所有查询结果并缓存。

            return self.__cache[#self.__cache - k + 1]
        end
    end
    mt.__cacheall = function(self)
        if self.__cachedone then return end -- 如果已缓存完毕则退出。

        if iqenum == nil then
            iqenum, iq, state = getmetatable(query).__enum, query, 0 -- 获取内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
        end

        local c = self.__cache -- 获取缓存数组。

        local next
        while true do
            state, next = iqenum(iq, state)
            if next == nil then break end

            table.insert(c, next) -- 向缓存数组中插入新项。
        end

        self.__cachedone = true -- 设置缓存完毕标识符。
    end
    mt.__enum = __enum
    mt.__reset = function(q)
        local __reset = getmetatable(query).__reset -- 获取重置元函数。
        if __reset then __reset(query) end -- 首先重置内部查询对象。

        local self = getmetatable(q)
        self.__cache = {}
        self.__cachedone = false

        iqenum, iq, state = nil, nil, nil
    end
    mt.__ipairs = __ipairs
    mt.__pairs = __pairs

    local qResult = {}
    luaq.util.attachLuaq(qResult, mt)

    return qResult
end

function luaq.aggregate(query, func, seed, ...)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("aggregate", 1, "查询对象", query, "(不是%s)。")
    end
    if type(func) ~= "function" then luaq.util.errBadArgType("aggregate", 2, "function", func) end
    if seed ~= nil or type(seed) ~= "table" then luaq.util.errBadArgValue("aggregate", 2, "合法的元组", query, "(不是%s)。") end

    local iqenum, iq, state = getmetatable(query).__enum, query, 0 -- 获取内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local _, result = iqenum(iq, 0)

    local result, next = seed, nil
    while true do
        state, next = iqenum(iq, state)
        if next == nil then break end
        if result then
            result = { func(state - 1, result, state, next) }
        else result = next
        end
    end

    if result == nil then return ...
    else return unpack(result)
    end
end

function luaq.reserve(query, ...)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("reserve", 1, "查询对象", query, "(不是%s)。")
    end

    local iqenum, iq, state -- 内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local default = { ... } -- 要预留的项。
    local mt = {
        __cache = {},
        __cachedone = false
    }
    mt.__index = __index
    mt.__cachetill = function(self, index)
        if self.__cachedone then return end -- 如果已缓存完毕则退出。
        if type(index) ~= "number" then luaq.util.errBadArgType("__cachetill", 2, "number", index) end
        if index <= 0 then luaq.util.errBadArgValue("__cachetill", 2, "正整数", index) end

        local c = self.__cache -- 获取缓存数组。
        if index <= #c then return end -- 如果指定索引小于已缓存项的数量,则直接退出。

        if iqenum == nil then
            iqenum, iq, state = getmetatable(query).__enum, query, 0 -- 获取内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
        end

        local next
        while index > #c do
            state, next = iqenum(iq, state)
            if next == nil then break end

            table.insert(c, { unpack(next) }) -- 向缓存数组中插入新项。
        end

        if next == nil then -- 当数组下一个项是nil时。
            if #c == 0 then -- 内部查询对象为空(缓存为空)
                table.insert(c, extra) -- 向缓存数组中插入预留项。
            end
            self.__cachedone = true -- 设置缓存完毕标识符
        end
    end
    mt.__enum = __enum
    mt.__reset = function(q)
        local __reset = getmetatable(query).__reset -- 获取重置元函数。
        if __reset then __reset(query) end -- 首先重置内部查询对象。

        local self = getmetatable(q)
        self.__cache = {}
        self.__cachedone = false

        iqenum, iq, state = nil, nil, nil
    end
    mt.__ipairs = __ipairs
    mt.__pairs = __pairs

    local qResult = {}
    luaq.util.attachLuaq(qResult, mt)

    return qResult
end

function luaq.first(query, ...)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("first", 1, "查询对象", query, "(不是%s)。")
    end

    local iqenum, iq = getmetatable(query).__enum, query -- 获取内部查询对象的枚举元函数以及固定值。
    local _, result = iqenum(iq, 0)

    if result == nil then return ...
    else return unpack(result)
    end
end

function luaq.last(query, ...)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("last", 1, "查询对象", query, "(不是%s)。")
    end

    local iqenum, iq, state = getmetatable(query).__enum, query, 0 -- 获取内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local result, next
    while true do
        state, next = iqenum(iq, state)
        if next == nil then break
        else result = next
        end
    end

    if result == nil then return ...
    else return unpack(result)
    end
end

function luaq.only(query, ...)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("only", 1, "查询对象", query, "(不是%s)。")
    end

    local iqenum, iq = getmetatable(query).__enum, query -- 获取内部查询对象的枚举元函数以及固定值。
    local state, result = iqenum(iq, 0)

    if result == nil or iqenum(iq, state) ~= nil then return ... -- 仅当不存在第一项或存在第二项时返回默认值。
    else return unpack(result)
    end
end

function luaq.sum(query, addition, ...)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("sum", 1, "查询对象", query, "(不是%s)。")
    end
    if type(addition) ~= "nil" and type(addition) ~= "function" then luaq.util.errBadArgType("average", 2, "nil或function", addition)
    end

    local iqenum, iq, state = getmetatable(query).__enum, query, 0 -- 获取内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local result, next
    while true do
        state, next = iqenum(iq, state)
        if next == nil then break end

        if result == nil then
            if addition == nil then
                local temp = {}
                local length = select("#", next)
                for _index = 1, length do
                    temp[_index] = tonumber(next[_index])
                end
                result = temp
            else result = next
            end
        else
            if addition == nil then
                local temp = {}
                local length = math.max(select("#", result), select("#", next))
                for _index = 1, length do
                    local v1, v2 = result[_index], tonumber(next[_index])
                    if v1 ~= nil and v2 ~= nil then
                        temp[_index] = v1 + v2
                    else
                        temp[_index] = v1 or v2
                    end
                end
            else result = addition(result, next)
            end
        end
    end

    if result == nil then return ...
    else return unpack(result)
    end
end

function luaq.average(query, addition, division, ...)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("average", 1, "查询对象", query, "(不是%s)。")
    end
    if addition == nil then division = nil -- 未提供求和函数时,使用默认的求和函数及求商函数。
    elseif type(addition) ~= "function" then luaq.util.errBadArgType("average", 2, "nil或function", addition)
    end
    if division ~= nil and type(division) ~= "function" then luaq.util.errBadArgType("average", 3, "nil或function", division) end

    local iqenum, iq, state = getmetatable(query).__enum, query, 0 -- 获取内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local result, count, next
    while true do
        state, next = iqenum(iq, state)
        if next == nil then break end

        if result == nil then
            if addition == nil then
                local temp = {}
                local length = select("#", next)
                for _index = 1, length do
                    temp[_index] = tonumber(next[_index])
                end
                result = temp
            else result = next
            end
        else
            if addition == nil then
                local temp = {}
                local length = math.max(select("#", result), select("#", next))
                for _index = 1, length do
                    local v1, v2 = result[_index], tonumber(next[_index])
                    if v1 ~= nil and v2 ~= nil then
                        temp[_index] = v1 + v2
                    else
                        temp[_index] = v1 or v2
                    end
                end
            else result = addition(result, next)
            end
        end

        count = count + 1
    end

    if result == nil then return ... end

    if division == nil then
        local length = select("#", result)
        for _index = 1, length do
            if result[_index] then
                result[_index] = result[_index] / count
            end
        end
    else result = division(unpack(result))
    end

    return unpack(result)
end

function luaq.max(query, comp, ...)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("max", 1, "查询对象", query, "(不是%s)。")
    end
    if comp ~= nil and type(comp) ~= "function" then luaq.util.errBadArgType("max", 2, "nil或function", comp) end

    local iqenum, iq, state = getmetatable(query).__enum, query, 0 -- 获取内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local result, next
    while true do
        state, next = iqenum(iq, state)
        if next == nil then break end

        if result == nil then result = next
        else
            if comp == nil then
                if luaq.util.compare(result, next) < 0 then
                    result = next
                end
            else
                local compTest = comp(result, next)
                if compTest == true or compTest < 0 then
                    result = next
                end
            end
        end
    end

    if result == nil then return ...
    else return unpack(result)
    end
end

function luaq.min(query, comp, ...)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("min", 1, "查询对象", query, "(不是%s)。")
    end
    if comp ~= nil and type(comp) ~= "function" then luaq.util.errBadArgType("min", 2, "nil或function", comp) end

    local iqenum, iq, state = getmetatable(query).__enum, query, 0 -- 获取内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local result, next
    while true do
        state, next = iqenum(iq, state)
        if next == nil then break end

        if result == nil then result = next
        else
            if comp == nil then
                if luaq.util.compare(result, next) > 0 then
                    result = next
                end
            else
                local compTest = comp(next, result)
                if compTest == true or compTest > 0 then
                    result = next
                end
            end
        end
    end

    if result == nil then return ...
    else return unpack(result)
    end
end

function luaq.sub(query, i, j)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("sub", 1, "查询对象", query, "(不是%s)。")
    end
    if type(i) ~= "number" then luaq.util.errBadArgType("sub", 2, "number", i)
    elseif i > 0 then i = math.ceil(i)
    elseif i < 0 then i = math.floor(i)
    else luaq.util.errBadArgValue("sub", 2, "非零的整数", i)
    end
    if j == nil then j = -1
    elseif type(j) ~= "number" then luaq.util.errBadArgType("sub", 3, "nil或number", j)
    elseif j > 0 then j = math.floor(j)
    elseif j < 0 then j = math.ceil(j)
    else luaq.util.errBadArgValue("sub", 3, "非零的整数", j)
    end

    local iqenum, iq, state -- 内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local buff = {}
    local mt = {
        __cache = {},
        __cachedone = false
    }
    mt.__index = __index
    mt.__cachetill = function(self, index)
        if self.__cachedone then return end -- 如果已缓存完毕则退出。
        if type(index) ~= "number" then luaq.util.errBadArgType("__cachetill", 2, "number", index) end
        if index <= 0 then luaq.util.errBadArgValue("__cachetill", 2, "正整数", index) end

        local c = self.__cache -- 获取缓存数组。
        if index <= #c then return end -- 如果指定索引小于已缓存项的数量,则直接退出。

        if iqenum == nil then
            iqenum, iq, state = getmetatable(query).__enum, query, 0 -- 获取内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
        end

        if ((i < 0) == (j < 0)) and i > j then -- 两个索引符号相同且起始索引大于结束索引,截取子串为空串。
            self.__cachedone = true -- 设置缓存完毕标识符。
            return
        end

        if i < 0 then -- 当起始索引为反向定位时,必须获得内部查询对象的所有项的数量。
            -- 缓存所有项。
            local count = 0
            while true do
                local next
                state, next = iqenum(iq, state)
                if next == nil then break -- 缓存结束分支。
                elseif j > 0 and count + i >= j then -- 计算得到起始索引大于结束索引。
                    self.__cachedone = true -- 设置缓存完毕标识符。
                    return
                end

                table.insert(buff, next)
                count = count + 1
            end

            local v1, v2 = i, j
            if i < 0 then v1 = count + i + 1 end -- 获得正向定位起始索引。
            if j < 0 then v2 = count + j + 1 end -- 获得正向定位结束索引。
            for _index = v1, v2 do
                local e = buff[_index]
                if e == nil then break end

                table.insert(c, { unpack(e) }) -- 向缓存数组中插入新项。
            end
            self.__cachedone = true -- 设置缓存完毕标识符。
        else
            local v1, v2 = i, j
            while (j < 0 or state < j) and index > #c do
                local next
                if j < 0 then v2 = state + j + 2 end -- 获得正向定位结束索引。
                state, next = iqenum(iq, state)
                if next == nil then
                    self.__cachedone = true -- 仅当数组下一个项是nil时设置缓存完毕标识符。
                    if v1 > v2 then return -- 计算得到起始索引大于结束索引。
                    else break
                    end
                elseif state >= v1 then
                    if j > 0 then
                        table.insert(c, { unpack(next) }) -- 向缓存数组中插入新项。
                    else
                        table.insert(buff, next)
                        if v2 >= v1 then
                            table.insert(c, { unpack(buff[v2 - v1 + 1]) }) -- 向缓存数组中插入新项。
                        end
                    end
                end
            end
        end
    end
    mt.__enum = __enum
    mt.__reset = function(q)
        local __reset = getmetatable(query).__reset -- 获取重置元函数。
        if __reset then __reset(query) end -- 首先重置内部查询对象。

        local self = getmetatable(q)
        self.__cache = {}
        self.__cachedone = false

        iqenum, iq, state = nil, nil, nil
        buff = {}
    end
    mt.__ipairs = __ipairs
    mt.__pairs = __pairs

    local qResult = {}
    luaq.util.attachLuaq(qResult, mt)

    return qResult
end

function luaq.skip(query, count, func)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("skip", 1, "查询对象", query, "(不是%s)。")
    end
    if type(count) ~= "number" then luaq.util.errBadArgType("skip", 2, "number", count)
    elseif count < 0 then luaq.util.errBadArgValue("skip", 2, "不是自然数", count)
    end
    if func ~= nil and type(func) ~= "function" then luaq.util.errBadArgType("skip", 3, "nil或function", func) end

    if func then
        query = query:where(func)
    end

    if count >= 0 then
        return query:sub(math.floor(count + 1))
    else
        return query:sub(1, math.ceil(count - 1))
    end
end

function luaq.take(query, count, func)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("take", 1, "查询对象", query, "(不是%s)。")
    end
    if type(count) ~= "number" then luaq.util.errBadArgType("take", 2, "number", count)
    elseif count < 0 then luaq.util.errBadArgValue("take", 2, "不是自然数", count)
    end
    if func ~= nil and type(func) ~= "function" then luaq.util.errBadArgType("take", 3, "nil或function", func) end

    if func then
        query = query:where(func)
    end

    if count >= 0 then
        return query:sub(1, math.floor(count))
    else
        return query:sub(math.ceil(count))
    end
end

function luaq.ofType(query, typename)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("ofType", 1, "查询对象", query, "(不是%s)。")
    end
    if type(typename) ~= "string" then luaq.util.errBadArgType("ofType", 2, "string", typename) end

    return query:where(function(_, e) return type(e) == typename end)
end

function luaq.query(query)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("query", 1, "查询对象", query, "(不是%s)。")
    end

    local tResult = {}
    for _, entry in enum(query) do
        table.insert(tResult, entry)
    end

    return tResult
end

function luaq.each(query, func)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("foreach", 1, "查询对象", query, "(不是%s)。")
    end
    if type(func) ~= "function" then luaq.util.errBadArgType("foreach", 2, "function", func) end

    local iqenum, iq, state = getmetatable(query).__enum, query, 0 -- 获取内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local next
    while true do
        state, next = iqenum(iq, state)
        if next == nil then break end

        func(state, unpack(next)) -- 调用操作函数。
    end
end

function luaq.has(query, func, ...)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("has", 1, "查询对象", query, "(不是%s)。")
    end
    if func ~= nil and type(func) ~= "function" then luaq.util.errBadArgType("has", 2, "nil或function", func) end

    local iqenum, iq, state = getmetatable(query).__enum, query, 0 -- 获取内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
    local entry = { ... }
    local next
    while true do
        state, next = iqenum(iq, state)
        if next == nil then break end

        if func then
            local evenTest = func(entry, next) -- 调用筛选函数。
            if evenTest == true or evenTest == 0 then return true end -- 找到相等项。
        else
            if luaq.util.equal(entry, next) then return true end -- 找到相等项。
        end
    end

    return false -- 未找到相等项。
end

function luaq.is(query, other, func, sequence)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("is", 1, "查询对象", query, "(不是%s)。")
    end
    if type(other) == "table" then
        if not isQuery(other) then
            other = luaq.iasQuery(other)
        end
    else
        luaq.util.errBadArgValue("is", 2, "查询对象", other, "(不是%s)。")
    end
    if sequence == nil then sequence = true
    elseif type(sequence) ~= "boolean" then
        luaq.util.errBadArgType("is", 4, "nil或boolean", sequence)
    end

    if sequence then
        local iqenum1, iq1, state1 = getmetatable(query).__enum, query, 0 -- 获取第一个内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
        local iqenum2, iq2, state2 = getmetatable(other).__enum, other, 0 -- 获取另一个内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
        local next1, next2
        while true do
            state1, next1 = iqenum1(iq1, state1)
            state2, next2 = iqenum2(iq2, state2)

            if next1 ~= nil and next2 ~= nil then
                local isEven
                if func then
                    local evenTest = func(next1, next2) -- 调用筛选函数。
                    isEven = evenTest == true or evenTest == 0
                else
                    isEven = luaq.util.equal(next1, next2)
                end
                if not isEven then return false end
            elseif (next1 == nil) ~= (next2 == nil) then return false
            end
            if next1 == nil or next2 == nil then break end
        end

        return true
    else
        -- 获取两个结果表,若长度不一致则不相等。
        local result1 = query:distinct(func):query()
        local result2 = other:distinct(func):query()
        if #result1 ~= #result2 then return false end

        for index1, entry1 in ipairs(result1) do
            for index2, entry2 in ipairs(result2) do
                if entry2 then -- 仅当entry2为table类型时才为真。(请不要轻易改动此表达式。)
                    local isEven
                    if func then
                        local evenTest = func(entry1, entry2) -- 调用筛选函数。
                        isEven = evenTest == true or evenTest == 0
                    else
                        isEven = luaq.util.equal(entry1, entry2)
                    end
                    if isEven then
                        result2[index2] = false -- 使得外层if条件永远为假。(请不要轻易改动此值。)
                        entry1 = nil -- 供外层for检测使用。(请不要轻易改动此值。)
                        break
                    end
                end
            end
            if entry1 then return false end -- 在内层for中未被设置为nil。(请不要轻易改动此表达式。)
        end

        return true
    end
end

local function isSubRelationship(query, other, func, sequence)
    if sequence then
        local iqenum1, iq1, state1 = getmetatable(query).__enum, query, 0 -- 获取第一个内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
        local iqenum2, iq2, state2 = getmetatable(other).__enum, other, 0 -- 获取另一个内部查询对象的枚举元函数、固定值以及迭代器的起始状态。
        local next1, next2
        state1, next1 = iqenum1(iq1, state1)
        state2, next2 = iqenum2(iq2, state2)
        local fstart = false -- 序列匹配开始标识符。
        while true do
            if next1 == nil then return true -- 子序列匹配到结尾。
            elseif next2 == nil then return false -- 子序列未匹配到结尾时,被检测序列到达结尾。
            else
                local isEven
                if func then
                    local evenTest = func(next1, next2) -- 调用筛选函数。
                    isEven = evenTest == true or evenTest == 0
                else
                    isEven = luaq.util.equal(next1, next2)
                end
                if isEven then
                    if not fstart then fstart = true end -- 匹配开始。
                    state1, next1 = iqenum1(iq1, state1) -- 子序列匹配指针向后移动一项。
                else
                    if fstart then -- 复位子序列匹配指针以及状态。
                        fstart = false
                        state1, next1 = iqenum1(iq1, 0)
                    end
                end
                state2, next2 = iqenum2(iq2, state2) -- 被检测序列指针向后移动一项。
            end
        end
    else
        -- 获取两个结果表。
        local result1 = query:distinct(func):query()
        local result2 = other:query()

        for index1, entry1 in ipairs(result1) do
            for index2, entry2 in ipairs(result2) do
                if entry2 then -- 仅当entry2为table类型时才为真。(请不要轻易改动此表达式。)
                    local isEven
                    if func then
                        local evenTest = func(entry1, entry2) -- 调用筛选函数。
                        isEven = evenTest == true or evenTest == 0
                    else
                        isEven = luaq.util.equal(entry1, entry2)
                    end
                    if isEven then
                        result2[index2] = false -- 使得外层if条件永远为假。(请不要轻易改动此值。)
                        entry1 = nil -- 供外层for检测使用。(请不要轻易改动此值。)
                        break
                    end
                end
            end
            if entry1 then return false end -- 在内层for中未被设置为nil。(请不要轻易改动此表达式。)
        end

        return true
    end
end
function luaq.subOf(query, other, func, sequence)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("subOf", 1, "查询对象", query, "(不是%s)。")
    end
    if type(other) == "table" then
        if not isQuery(other) then
            other = luaq.iasQuery(other)
        end
    else
        luaq.util.errBadArgValue("subOf", 2, "查询对象", other, "(不是%s)。")
    end
    if sequence == nil then sequence = true
    elseif type(sequence) ~= "boolean" then
        luaq.util.errBadArgType("subOf", 4, "nil或boolean", sequence)
    end

    local rel = isSubRelationship(query, other, func, sequence)
    return rel
end

function luaq.superOf(query, other, func, sequence)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("superOf", 1, "查询对象", query, "(不是%s)。")
    end
    if type(other) == "table" then
        if not isQuery(other) then
            other = luaq.iasQuery(other)
        end
    else
        luaq.util.errBadArgValue("superOf", 2, "查询对象", other, "(不是%s)。")
    end
    if sequence == nil then sequence = true
    elseif type(sequence) ~= "boolean" then
        luaq.util.errBadArgType("superOf", 4, "nil或boolean", sequence)
    end

    local rel = isSubRelationship(other, query, func, sequence)
    return rel
end

function luaq.properSubOf(query, other, func, sequence)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("properSubOf", 1, "查询对象", query, "(不是%s)。")
    end
    if type(other) == "table" then
        if not isQuery(other) then
            other = luaq.iasQuery(other)
        end
    else
        luaq.util.errBadArgValue("properSubOf", 2, "查询对象", other, "(不是%s)。")
    end
    if sequence == nil then sequence = true
    elseif type(sequence) ~= "boolean" then
        luaq.util.errBadArgType("properSubOf", 4, "nil或boolean", sequence)
    end

    local rel, proper = isSubRelationship(query, other, func, sequence)
    return rel and proper
end

function luaq.properSuperOf(query, other, func, sequence)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("properSuperOf", 1, "查询对象", query, "(不是%s)。")
    end
    if type(other) == "table" then
        if not isQuery(other) then
            other = luaq.iasQuery(other)
        end
    else
        luaq.util.errBadArgValue("properSuperOf", 2, "查询对象", other, "(不是%s)。")
    end
    if sequence == nil then sequence = true
    elseif type(sequence) ~= "boolean" then
        luaq.util.errBadArgType("properSuperOf", 4, "nil或boolean", sequence)
    end

    local rel, proper = isSubRelationship(other, query, func, sequence)
    return rel and proper
end

function luaq.overlap(query, other, func, sequence)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("overlap", 1, "查询对象", query, "(不是%s)。")
    end
    if type(other) == "table" then
        if not isQuery(other) then
            other = luaq.iasQuery(other)
        end
    else
        luaq.util.errBadArgValue("overlap", 2, "查询对象", other, "(不是%s)。")
    end
    if sequence == nil then sequence = true
    elseif type(sequence) ~= "boolean" then
        luaq.util.errBadArgType("overlap", 4, "nil或boolean", sequence)
    end

    -- 获取两个结果表。
    local result1 = query:distinct(func):query()
    local result2 = other:distinct(func):query()
    if #result1 == 0 or #result2 == 0 then return false end -- 任何一个为空集时两者不相交。

    if sequence then
        for i = 1, 5 do
            local entry, seq
            if i == 1 then entry, seq = result1[1], result2
            elseif i == 2 then entry, seq = result1[#result1], result2
            elseif i == 3 then entry, seq = result2[1], result1
            elseif i == 4 then etnry, seq = result2[#result2], result1
            else return false -- 四种情况均未发现相等项,则两者不相交。
            end

            for _, seqEntry in ipairs(seq) do
                local isEven
                if func then
                    local evenTest = func(entry, seqEntry) -- 调用筛选函数。
                    isEven = evenTest == true or evenTest == 0
                else
                    isEven = luaq.util.equal(entry, seqEntry)
                end
                if isEven then return true end -- 发现相等项,两者相交。
            end
        end
    else
        for index1, entry1 in ipairs(result1) do
            for index2, entry2 in ipairs(result2) do
                local isEven
                if func then
                    local evenTest = func(entry1, entry2) -- 调用筛选函数。
                    isEven = evenTest == true or evenTest == 0
                else
                    isEven = luaq.util.equal(entry1, entry2)
                end
                if isEven then return true end -- 发现相等项,两者相交。
            end
        end

        return false
    end
end

-- 查询对象的默认链接元函数。(必须提供concat、append、prepend函数的实现。)
local function __concat(l, r)
    local v1, v2 = isQuery(l), isQuery(r)

    if v1 and v2 then return l:concat(r)
    elseif v1 and not v2 then return l:append(r)
    elseif not v1 and v2 then return l:prepend(r)
    else
        luaq.util.errBadArgValue("__concat", 1, "查询对象", l, "(不是%s)。")
    end
end

-- 查询对象的默认乘运算元函数。(必须提供join、duplicate函数的实现。)
local function __mul(l, r)
    local v1, v2 = isQuery(l), isQuery(r)

    if v1 and v2 then return l:join(r)
    elseif v1 and type(v2) == "number" then return l:duplicate(r)
    elseif v2 and type(v1) == "number" then return r:duplicate(l)
    elseif v1 then
        luaq.util.errBadArgValue("__mul", 1, "查询对象", l, "(不是%s)。")
    else
        luaq.util.errBadArgType("__mul", 1, "number", l)
    end
end

-- 查询对象的默认商运算元函数。(必须提供groupBy函数的实现。)
local function __div(query, key)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("__div", 1, "查询对象", query, "(不是%s)。")
    end
    if key == nil then luaq.util.errBadArgType("__div", 2, "非nil", key) end

    local func
    if type(key) == "function" then
        func = key
    else
        func = function(_, item)
            if type(item) == "table" then return item[key]
            else return nil
            end
        end
    end

    query:groupBy(func)
end

-- 查询对象的默认字符串元函数。
local function __tostring(query)
    if type(query) == "table" then
        if not isQuery(query) then
            query = luaq.iasQuery(query)
        end
    else
        luaq.util.errBadArgValue("__tostring", 1, "查询对象", query, "(不是%s)。")
    end

    return mw.dumpObject(query:query())
end

function luaq.util.attachLuaq(q, mt)
    q.asQuery = luaq.asQuery
    q.select = luaq.select
    q.selectMany = luaq.selectMany
    q.selectYield = luaq.selectYield
    q.where = luaq.where
    q.count = luaq.count
    q.any = luaq.any
    q.all = luaq.all
    q.groupBy = luaq.groupBy
    q.orderBy = luaq.orderBy
    q.thenBy = luaq.thenBy
    q.distinct = luaq.distinct
    q.reverse = luaq.reverse
    q.concat = luaq.concat
    q.append = luaq.append
    q.prepend = luaq.prepend
    q.aggregate = luaq.aggregate
    q.reserve = luaq.reserve
    q.duplicate = luaq.duplicate
    --q.join = luaq.join
    --q.groupJoin = luaq.groupJoin
    q.first = luaq.first
    q.last = luaq.last
    q.only = luaq.only
    q.sum = luaq.sum
    q.average = luaq.average
    q.max = luaq.max
    q.min = luaq.min
    q.sub = luaq.sub
    q.skip = luaq.skip
    q.take = luaq.take
    q.ofType = luaq.ofType
    q.query = luaq.query
    q.each = luaq.each
    q.has = luaq.has
    --q.union = luaq.union
    --q.except = luaq.except
    --q.symmetricExcept = luaq.symmetricExcept
    --q.intersect = luaq.intersect
    --q.complement = luaq.complement
    q.is = luaq.is
    q.subOf = luaq.subOf
    q.superOf = luaq.superOf
    q.properSubOf = luaq.properSubOf
    q.properSuperOf = luaq.properSuperOf
    q.overlap = luaq.overlap

    mt.__add = luaq.union
    mt.__sub = luaq.except
    mt.__mul = __mul
    mt.__div = __div
    mt.__unm = luaq.reverse
    mt.__mod = luaq.ofType
    mt.__power = luaq.join
    mt.__concat = __concat
    mt.__eq = luaq.is
    mt.lt = luaq.properSubOf
    mt.le = luaq.subOf
    mt.tostring = __tostring

    setmetatable(q, mt)
end

return luaq