Module:CargoTest2

From Noita Wiki
Jump to navigation Jump to search

Documentation for this module may be created at Module:CargoTest2/doc

local p = {}
local cargo = mw.ext.cargo

--[[-- Rather important requirements --]]--
local ytils = require('Module:Y_util');
local inft  = require('Module:Infotable');

local ydebug,ytable,yxml,ystr = ytils.debug, ytils.table, ytils.xml, ytils.string;

--[[
https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Frame_object
https://www.mediawiki.org/wiki/Extension:Cargo/Other_features#Lua_support

Relevant non-LUA/PHP Documentation:
https://www.mediawiki.org/wiki/Extension:Cargo/Querying_data
https://www.w3schools.com/sql/sql_where.asp
https://www.w3schools.com/sql/sql_operators.asp

`fields` is comma separated array of fields that we want to get from the table
- supports setting an alias for field `fields=_pageName=PGNM,Field2`
- no clue why you would do that, so do not do that.
`where` is an array of conditions, where the field values have to match for the field to be
- returned where params are separated with AND / OR
`orderBy` is comma separated array of fields
`limit` limits results, wow

example where strings (essentially SQL with = between WHERE and the conditions):
`WHERE=type LIKE 'Proj%' AND id LIKE '%blood%'`
- gets Projectiles, Projectile Modifiers, whose ID contains word blood
- % matches any or 0 characters in LIKE statements
`WHERE=sortKey='pathseeker'`
- gets all sort keys with pathseeker

HOLDS operator is Cargo builtin for querying fields containing comma separated values
Since `fields=` directly maps to SQL `SELECT`,
it is possible to use `fields=*` to get all fields
]]--

local function getTabbedVars( table2d )
  local tab = 1;
  local varsExist,vars = {},{};
  if( type(table2d)=="table") then
    for _,table1d in pairs(table2d) do
      if( type(table1d)=="table") then
        for prop,pval in pairs(table1d) do
          local data = "";
          if type(pval)=="string" or type(pval)=="number" then
            data = tostring(pval);
          end
          varsExist[prop] = true;
          vars[prop.."_"..tab] = data;
        end
      end
      tab = tab + 1;
    end
  end
  return {
    tab_count=tab-1,
    tab_vars=vars,
    v_exists=varsExist,
  };
end 

--[[  Cargo Query Source Code For Supported Options
--  https://github.com/wikimedia/mediawiki-extensions-Cargo/blob/master/includes/CargoLuaLibrary.php
--]]
local mdl_enabledCargoQueryArgs = {
  "where",
  "orderBy",
  "limit",
--  "offset"
--  "join",
--  "groupBy",
--  "having",
};
local function doCargoQuery( frameInvoke ) -- returns table2d: { spells(tabs)->{ variables } }
  local res = nil;
  if( frameInvoke ~= nil
  and ystr.isStrExist(frameInvoke.tables)
  and ystr.isStrExist(frameInvoke.fields)
  and ystr.isStrExist(frameInvoke.where ) ) then
    local cargoQueryArgs = {};
    for _, arg in pairs(mdl_enabledCargoQueryArgs) do
      if( ystr.isStrExist(frameInvoke[ arg ]) ) then
        cargoQueryArgs[ arg ] = frameInvoke[ arg ];
      end
    end
    res = cargo.query( -- for some reason the lua query splits the tables
      frameInvoke.tables,    -- and fields from the rest of the supported
      frameInvoke.fields,    -- arguments, which are all then passed into
      cargoQueryArgs         -- the function separately in a table
    );
  end
  return res;
end

local mdl_blacklistCargoQueryArgs = {
  "limit",
};
local mdl_optionKeyword = "box";
local mdl_debugKeyword = "debugging";
function p.Generate( frame )
  local res = "Invoke Missing Arguments!";
  if( frame == nil ) then
    res = "No frame found, everything has broken down.";
  else
    if( frame.args ~= nil ) then
      local frameInvoke = {};
      local option = frame.args[ mdl_optionKeyword ];
      if( ystr.isStrExist( option ) ) then
        local test = inft.InvokeOpts[ option ];
        if( test ~= nil ) then
          frameInvoke = test;
        end
      end
      local loopcount, looplimit = 0, 50;
      for k,v in pairs(frame.args) do
        loopcount = loopcount + 1;
        if( looplimit < loopcount ) then break; end
        if( ystr.isStrExist( k )
        and ystr.isStrExist( v )
        and not(ytable.hasValue( mdl_blacklistCargoQueryArgs, k )) ) then
          frameInvoke[ k ] = v;
        end
      end
      if( frameInvoke.fields == "*" ) then
        local availableFields = ytable.getAllValStr( inft.TableField[ frameInvoke.tables ], frameInvoke.depth );
        if( availableFields ~= nil ) then
          frameInvoke.fields = table.concat( availableFields, "," );
        end
      end
      res = "Query returned nothing!";
      local cargoTable = doCargoQuery( frameInvoke ); -- a plain table2d
      local vadata = getTabbedVars( cargoTable );

      vadata.frame = frame;
      vadata.table = string.match(frameInvoke.tables, "^([^,]*),?"); -- first table only
      vadata.limit = ( frameInvoke.limit or 20   );
      vadata.lang  = ( frameInvoke.lang  or "en" );

      res = yxml.reindent( inft.Infobox[option]( vadata, frameInvoke ) ); -- infobox generator, see Module:Infotable

      -- Debugging
      local dbgLv = frameInvoke[ mdl_debugKeyword ];
      if( dbgLv ~= nil ) then
        local result = res;
        if( ystr.isStrExist(result) ) then
          result = result:gsub("<","&lt;"):gsub(">","&gt;");
        end
        res = "<div style=\"background-color:rgba(0,23,23,0.9);border:0.2em dashed #444;padding:1em;word-break:break-word;\">";
        if( dbgLv:match("1") ) then res = res.."<br />\nDBG:frame\n<br />"     ..ydebug.e2json( frame ); end
        if( dbgLv:match("2") ) then res = res.."<br />\nDBG:fInvoke\n<br />"   ..ydebug.e2json( frameInvoke ); end
        if( dbgLv:match("3") ) then res = res.."<br />\nDBG:cargoTable\n<br />"..ydebug.e2json( cargoTable ); end
        if( dbgLv:match("4") ) then res = res.."<br />\nDBG:vadata\n<br />"    ..ydebug.e2json( vadata ); end
        if( dbgLv:match("5") ) then res = res.."<br />\nDBG:result\n<br />"    ..ydebug.e2json( result ); end
        res = res.."</div>";
      end

    end
  end
  return res;
end

return p;