Module:Item util: Difference between revisions

From Path of Exile Wiki
Jump to navigation Jump to search
No edit summary
(Use new error object from Module:Util. Return the error object instead of the output string and let the calling module decide what to do with it.)
 
(One intermediate revision by the same user not shown)
Line 110: Line 110:
     -- Append to join, where and orderBy clauses
     -- Append to join, where and orderBy clauses
     if qargs.join then
     if qargs.join then
         query.join = table.concat({query.join or '', qargs.join}, ', ')
        -- m_util.table.merge rebuilds the table, which removes empty values
        -- TODO: Use a better function than m_util.table.merge
         query.join = table.concat(m_util.table.merge({query.join, qargs.join}), ', ')
     end
     end
     if qargs.where then
     if qargs.where then
         query.where = table.concat({query.where or '', qargs.where}, ' AND ')
         query.where = table.concat(m_util.table.merge({query.where, qargs.where}), ' AND ')
     end
     end
     if qargs.orderBy then
     if qargs.orderBy then
         query.orderBy = table.concat({qargs.orderBy or '', query.orderBy}, ', ')
         query.orderBy = table.concat(m_util.table.merge({qargs.orderBy, query.orderBy}), ', ')
     end
     end
     results = m_cargo.query(tables, fields, query)
     results = m_cargo.query(tables, fields, query)
Line 122: Line 124:
     if #results == 0 then
     if #results == 0 then
         -- No results found
         -- No results found
         err = m_util.misc.raise_error_or_return{
         err = m_util.Error{
             raise_required = true,
             message = string.format(
            args = args,
            msg = string.format(
                 i18n.errors.no_results_found,
                 i18n.errors.no_results_found,
                 search_param,
                 search_param,
                 args[search_param]
                 args[search_param]
             )
             ),
         }
            code = 'no_results_found',
            issue = args.issue_all_errors or false,
            category = i18n.categories.failed_query,
         }:throw()
     elseif #results > 1 then
     elseif #results > 1 then
         -- More than one result found
         -- More than one result found
Line 148: Line 151:
         end
         end
         if (map_count == 0 or map_count ~= #results) and drop_enabled_count ~= 1 then
         if (map_count == 0 or map_count ~= #results) and drop_enabled_count ~= 1 then
             err = m_util.misc.raise_error_or_return{
             err = m_util.Error{
                 raise_required = true,
                 message = string.format(
                args = args,
                msg = string.format(
                     i18n.errors.many_results_found,
                     i18n.errors.many_results_found,
                     search_param,
                     search_param,
                     args[search_param]
                     args[search_param]
                 )
                 ),
             }
                code = 'many_results_found',
                issue = args.issue_all_errors or false,
                category = i18n.categories.failed_query,
             }:throw()
         end
         end
     end
     end
Line 162: Line 166:
         mw.logObject(results)
         mw.logObject(results)
     end
     end
     if err ~= nil then
     if err then
        if not m_util.cast.boolean(args.nocat) then
            err = err .. m_util.misc.add_category({args.error_category or i18n.categories.failed_query})
        end
         return {error = err}
         return {error = err}
     end
     end

Latest revision as of 19:36, 13 December 2022

Module documentation[view] [edit] [history] [purge]


This is a meta module.

This module is meant to be used only by other modules. It should not be invoked in wikitext.

Lua logo

This module depends on the following other modules:

This meta module provides utility functions for modules that deal with items.

Usage

This module should be loaded with require().

-------------------------------------------------------------------------------
-- 
--                              Module:Item util
-- 
-- This meta module contains utility functions for modules that deal with items
-------------------------------------------------------------------------------

local m_util = require('Module:Util')
local m_cargo -- Lazy load require('Module:Cargo')

-- Should we use the sandbox version of our submodules?
local use_sandbox = m_util.misc.maybe_sandbox('Item util')

-- The cfg table contains all localisable strings and configuration, to make it
-- easier to port this module to another wiki.
local cfg = use_sandbox and mw.loadData('Module:Item util/config/sandbox') or mw.loadData('Module:Item util/config')

local i18n = cfg.i18n

-- ----------------------------------------------------------------------------
-- Exported functions
-- ----------------------------------------------------------------------------

local m = {}

function m.get_item_namespaces(args)
    -- Returns item namespaces from config as a table or as a comma-separated string
    args.format = args.format or 'table'
    if args.format == 'list' then
        return cfg.item_namespaces_list
    end
    return cfg.item_namespaces
end

function m.query_item(args, qargs)
    qargs = qargs or {}
    m_cargo = m_cargo or require('Module:Cargo')
    if not m_util.table.has_any_key(args, cfg.search_terms) then
        error(i18n.errors.missing_search_term)
    end
    local tables = {'items'}
    local fields = {
        'items._pageName=_pageName',
        'items.drop_enabled=drop_enabled',
        'items.class_id=class_id',
    }
    local query = {
        groupBy = 'items._pageID',
        orderBy = 'items.drop_enabled DESC',
    }
    local search_param
    local results
    if args.metadata_id then
        query.where = string.format(
            'items.metadata_id = "%s"',
            args.metadata_id
        )
        search_param = 'metadata_id'
    elseif args.page then
        -- Join with _pageData in order to check for page redirect
        tables[#tables+1] = '_pageData'
        query.join = 'items._pageName = _pageData._pageNameOrRedirect'
        query.where = string.format(
            '_pageData._pageName = "%s"',
            m_cargo.addslashes(args.page)
        )
        search_param = 'page'
    else
        tables[#tables+1] = 'maps'
        tables[#tables+1] = 'map_series'
        query.join = 'items._pageID = maps._pageID, maps.series = map_series.name'
        query.where = string.format(
            'items._pageNamespace IN (%s)',
            m.get_item_namespaces{format = 'list'}
        )
        query.orderBy = 'map_series.ordinal DESC, ' .. query.orderBy
        if args.item_name_exact then
            query.where = query.where .. string.format(
                ' AND items.name = "%s"',
                m_cargo.addslashes(args.item_name_exact)
            )
            search_param = 'item_name_exact'
        else
            --[[
            Cargo's implementation of HOLDS breaks when there is a properly 
            escaped quotation mark at the end of a string literal.

            Example of a WHERE clause that results in an error:
                items.name_list HOLDS "\"O\' Eternal\""

            Instead, we avoid using HOLDS by explicitly joining the child table 
            and then comparing using a native operator.
            --]]
            tables[#tables+1] = 'items__name_list'
            query.join = query.join .. ', items._ID = items__name_list._rowID'
            query.where = query.where .. string.format(
                ' AND items__name_list._value = "%s"',
                m_cargo.addslashes(args.item_name)
            )
            search_param = 'item_name'
        end
    end
    -- Append additional tables and fields
    if type(qargs.tables) == 'table' and #qargs.tables > 0 then
        tables = m_util.table.merge(tables, qargs.tables)
    end
    if type(qargs.fields) == 'table' and #qargs.fields > 0 then
        fields = m_util.table.merge(fields, qargs.fields)
    end
    -- Append to join, where and orderBy clauses
    if qargs.join then
        -- m_util.table.merge rebuilds the table, which removes empty values
        -- TODO: Use a better function than m_util.table.merge
        query.join = table.concat(m_util.table.merge({query.join, qargs.join}), ', ')
    end
    if qargs.where then
        query.where = table.concat(m_util.table.merge({query.where, qargs.where}), ' AND ')
    end
    if qargs.orderBy then
        query.orderBy = table.concat(m_util.table.merge({qargs.orderBy, query.orderBy}), ', ')
    end
    results = m_cargo.query(tables, fields, query)
    local err
    if #results == 0 then
        -- No results found
        err = m_util.Error{
            message = string.format(
                i18n.errors.no_results_found,
                search_param,
                args[search_param]
            ),
            code = 'no_results_found',
            issue = args.issue_all_errors or false,
            category = i18n.categories.failed_query,
        }:throw()
    elseif #results > 1 then
        -- More than one result found
        -- 
        -- If results are all maps, use the one from the most recent map
        -- series, regardless of whether it's drop enabled. Otherwise, 
        -- if only one of the results is drop enabled then use that one.
        local map_count = 0
        local drop_enabled_count = 0
        for i, v in ipairs(results) do
            if v.class_id == 'Map' then
                map_count = map_count + 1
            end
            if m_util.cast.boolean(v.drop_enabled) then
                drop_enabled_count = drop_enabled_count + 1
            end
        end
        if (map_count == 0 or map_count ~= #results) and drop_enabled_count ~= 1 then
            err = m_util.Error{
                message = string.format(
                    i18n.errors.many_results_found,
                    search_param,
                    args[search_param]
                ),
                code = 'many_results_found',
                issue = args.issue_all_errors or false,
                category = i18n.categories.failed_query,
            }:throw()
        end
    end
    if args.debug then
        mw.logObject(results)
    end
    if err then
        return {error = err}
    end
    return results[1] -- orderBy ensures that the first result is the one we want
end

return m