Module:Item util

From Path of Exile 2 Wiki
Revision as of 15:52, 18 January 2022 by Vinifera7 (talk | contribs)
Jump to navigation Jump to search
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)
    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',
    }
    if type(args.fields) == 'table' and #args.fields > 0 then
        fields = m_util.table.merge(fields, args.fields)
    end
    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, items.drop_enabled DESC'
        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
            query.where = query.where .. string.format(
                ' AND items.name_list HOLDS "%s"',
                m_cargo.addslashes(args.item_name)
            )
            search_param = 'item_name'
        end
    end
    results = m_cargo.query(tables, fields, query)
    local err
    if #results == 0 then
        -- No results found
        err = m_util.misc.raise_error_or_return{
            raise_required = true,
            args = args,
            msg = string.format(
                i18n.errors.no_results_found,
                search_param,
                args[search_param]
            )
        }
    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['items.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.misc.raise_error_or_return{
                raise_required = true,
                args = args,
                msg = string.format(
                    i18n.errors.many_results_found,
                    search_param,
                    args[search_param]
                )
            }
        end
    end
    if err ~= nil and not m_util.cast.boolean(args.nocat) then
        return {error = err .. m_util.misc.add_category({args.error_category or i18n.categories.failed_query}) }
    end
    return results[1] -- orderBy ensures that the first result is the one we want
end

return m