Module:SMWUtils

Revision as of 06:57, 15 January 2026 by Arclight-MCP-Bot (talk | contribs) (Create SMW utility module with findAllWithMin and findAllWithMax functions (via create-page on MediaWiki MCP Server))
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

-- Module:SMWUtils -- Utility functions for Semantic MediaWiki queries -- Includes helpers for finding all results matching min/max values

local p = {}

local function trim(s)

   if s == nil then return nil end
   s = tostring(s)
   s = s:gsub('^%s+', ):gsub('%s+$', )
   if s ==  then return nil end
   return s

end

--- Find all results where a property equals its minimum value across the result set -- @param frame Frame object with args: -- conditions: SMW query conditions (e.g., "Component (YPbPr)") -- minProperty: Property to find minimum of (e.g., "Has CRT model.Has screen size inches") -- printouts: Comma-separated list of properties to display -- format: Output format (table, ul, ol) - default "table" -- headers: Comma-separated header names for table format -- @return Wikitext output function p.findAllWithMin(frame)

   local args = frame.args
   local conditions = trim(args.conditions) or 
   local minProperty = trim(args.minProperty)
   local printouts = trim(args.printouts) or 
   local format = trim(args.format) or 'table'
   local headers = trim(args.headers) or 
   
   if not minProperty then
       return 'Error: minProperty is required'
   end
   
   -- Build the printout list
   local printoutList = {}
   for prop in printouts:gmatch('[^,]+') do
       table.insert(printoutList, '?' .. trim(prop))
   end
   -- Always include the minProperty for comparison
   table.insert(printoutList, '?' .. minProperty)
   
   -- Build and execute the query
   local queryString = conditions .. '\n' .. table.concat(printoutList, '\n') .. '\n|limit=500'
   local results = mw.smw.ask(queryString)
   
   if not results or #results == 0 then
       return "No results found."
   end
   
   -- Find the minimum value
   local minValue = nil
   for _, row in ipairs(results) do
       local val = row[minProperty]
       if val then
           local numVal = tonumber(val)
           if numVal then
               if minValue == nil or numVal < minValue then
                   minValue = numVal
               end
           end
       end
   end
   
   if minValue == nil then
       return "Could not determine minimum value."
   end
   
   -- Filter results to only those matching the minimum
   local filtered = {}
   for _, row in ipairs(results) do
       local val = row[minProperty]
       if val and tonumber(val) == minValue then
           table.insert(filtered, row)
       end
   end
   
   -- Build output based on format
   local headerList = {}
   for h in headers:gmatch('[^,]+') do
       table.insert(headerList, trim(h))
   end
   
   local printoutProps = {}
   for prop in printouts:gmatch('[^,]+') do
       table.insert(printoutProps, trim(prop))
   end
   
   if format == 'table' then
       return p._formatTable(filtered, printoutProps, headerList, minProperty, minValue)
   elseif format == 'ul' or format == 'ol' then
       return p._formatList(filtered, printoutProps, format, minProperty, minValue)
   else
       return p._formatTable(filtered, printoutProps, headerList, minProperty, minValue)
   end

end

--- Find all results where a property equals its maximum value function p.findAllWithMax(frame)

   local args = frame.args
   local conditions = trim(args.conditions) or 
   local maxProperty = trim(args.maxProperty)
   local printouts = trim(args.printouts) or 
   local format = trim(args.format) or 'table'
   local headers = trim(args.headers) or 
   
   if not maxProperty then
       return 'Error: maxProperty is required'
   end
   
   -- Build the printout list
   local printoutList = {}
   for prop in printouts:gmatch('[^,]+') do
       table.insert(printoutList, '?' .. trim(prop))
   end
   table.insert(printoutList, '?' .. maxProperty)
   
   -- Build and execute the query
   local queryString = conditions .. '\n' .. table.concat(printoutList, '\n') .. '\n|limit=500'
   local results = mw.smw.ask(queryString)
   
   if not results or #results == 0 then
       return "No results found."
   end
   
   -- Find the maximum value
   local maxValue = nil
   for _, row in ipairs(results) do
       local val = row[maxProperty]
       if val then
           local numVal = tonumber(val)
           if numVal then
               if maxValue == nil or numVal > maxValue then
                   maxValue = numVal
               end
           end
       end
   end
   
   if maxValue == nil then
       return "Could not determine maximum value."
   end
   
   -- Filter results to only those matching the maximum
   local filtered = {}
   for _, row in ipairs(results) do
       local val = row[maxProperty]
       if val and tonumber(val) == maxValue then
           table.insert(filtered, row)
       end
   end
   
   -- Build output
   local headerList = {}
   for h in headers:gmatch('[^,]+') do
       table.insert(headerList, trim(h))
   end
   
   local printoutProps = {}
   for prop in printouts:gmatch('[^,]+') do
       table.insert(printoutProps, trim(prop))
   end
   
   if format == 'table' then
       return p._formatTable(filtered, printoutProps, headerList, maxProperty, maxValue)
   elseif format == 'ul' or format == 'ol' then
       return p._formatList(filtered, printoutProps, format, maxProperty, maxValue)
   else
       return p._formatTable(filtered, printoutProps, headerList, maxProperty, maxValue)
   end

end

-- Internal: Format results as a wikitable function p._formatTable(results, printouts, headers, valueProperty, value)

   local html = mw.html.create('div')
   html:wikitext("Showing all results where " .. valueProperty .. " = " .. tostring(value) .. ":\n\n")
   
   local tbl = html:tag('table')
   tbl:addClass('wikitable'):addClass('sortable')
   
   -- Header row
   local headerRow = tbl:tag('tr')
   headerRow:tag('th'):wikitext('#')
   for i, prop in ipairs(printouts) do
       local headerText = headers[i] or prop:gsub('.*%.', ):gsub('Has ', )
       headerRow:tag('th'):wikitext(headerText)
   end
   
   -- Data rows
   for i, row in ipairs(results) do
       local tr = tbl:tag('tr')
       tr:tag('td'):wikitext(tostring(i))
       for _, prop in ipairs(printouts) do
           local val = row[prop]
           local displayVal = 
           if val then
               if type(val) == 'table' then
                   -- Handle linked values (pages)
                   if val.fulltext then
                       displayVal = '' .. val.fulltext .. ''
                   else
                       displayVal = table.concat(val, ', ')
                   end
               else
                   displayVal = tostring(val)
               end
           end
           tr:tag('td'):wikitext(displayVal)
       end
   end
   
   return tostring(html)

end

-- Internal: Format results as a list function p._formatList(results, printouts, listType, valueProperty, value)

   local tag = listType == 'ol' and 'ol' or 'ul'
   
   local html = mw.html.create('div')
   html:wikitext("Showing all results where " .. valueProperty .. " = " .. tostring(value) .. ":\n\n")
   
   local list = html:tag(tag)
   
   for _, row in ipairs(results) do
       local li = list:tag('li')
       local parts = {}
       for _, prop in ipairs(printouts) do
           local val = row[prop]
           if val then
               if type(val) == 'table' and val.fulltext then
                   table.insert(parts, '' .. val.fulltext .. '')
               else
                   table.insert(parts, tostring(val))
               end
           end
       end
       li:wikitext(table.concat(parts, ' - '))
   end
   
   return tostring(html)

end

return p

MediaWiki Appliance - Powered by TurnKey Linux