Jump to content

Module:Wikibase

From HxmnWiki

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

-- Module:Wikibase - fetches data from Wikibase SPARQL endpoint
-- Usage: {{#invoke:Wikibase|countries}} or {{#invoke:Wikibase|cities}}
local p = {}
local ed = mw.ext.externalData

local SPARQL_URL = "https://wd.hxmn.dev/query/sparql?format=json"
local WB_URL = "https://wd.hxmn.dev"

-- Run a SPARQL query via External Data and return rows
local function sparql(query, fields)
    local params = {
        url = SPARQL_URL,
        format = "json with jsonpath",
        ["post data"] = "query=" .. query,
        data = fields
    }
    local values, errors = ed.getWebData(params)
    if errors and #errors > 0 then
        return nil, errors[1]
    end
    return values
end

-- Format number with comma separators
local function formatNumber(s)
    if not s or s == "" then return "" end
    local n = tonumber(s)
    if not n then return s end
    local formatted = tostring(math.floor(n))
    local k
    while true do
        formatted, k = formatted:gsub("^(-?%d+)(%d%d%d)", "%1,%2")
        if k == 0 then break end
    end
    return formatted
end

-- Extract QID from full entity URI
local function qid(uri)
    if not uri or uri == "" then return "" end
    return uri:match("([PQ]%d+)$") or uri
end

-- Build a wikitext link to a Wikibase item
local function wblink(uri)
    local id = qid(uri)
    if id == "" then return "" end
    return "[" .. WB_URL .. "/wiki/Item:" .. id .. " " .. id .. "]"
end

function p.countries(frame)
    local query = [==[SELECT ?item ?itemLabel ?capitalLabel ?population ?founded ?continentLabel WHERE { ?item <https://wd.hxmn.dev/prop/direct/P1> <https://wd.hxmn.dev/entity/Q1> . ?item <http://www.w3.org/2000/01/rdf-schema#label> ?itemLabel . FILTER(LANG(?itemLabel) = 'en') OPTIONAL { ?item <https://wd.hxmn.dev/prop/direct/P5> ?capital . ?capital <http://www.w3.org/2000/01/rdf-schema#label> ?capitalLabel . FILTER(LANG(?capitalLabel) = 'en') } OPTIONAL { ?item <https://wd.hxmn.dev/prop/direct/P3> ?population . } OPTIONAL { ?item <https://wd.hxmn.dev/prop/direct/P4> ?founded . } OPTIONAL { ?item <https://wd.hxmn.dev/prop/direct/P6> ?continent . ?continent <http://www.w3.org/2000/01/rdf-schema#label> ?continentLabel . FILTER(LANG(?continentLabel) = 'en') } } ORDER BY ?itemLabel]==]
    local fields = "item=$.results.bindings[*].item.value,name=$.results.bindings[*].itemLabel.value,capital=$.results.bindings[*].capitalLabel.value,population=$.results.bindings[*].population.value,founded=$.results.bindings[*].founded.value,continent=$.results.bindings[*].continentLabel.value"

    local rows, err = sparql(query, fields)
    if err then return '<span class="error">SPARQL error: ' .. tostring(err) .. '</span>' end
    if not rows then return "No data returned from Wikibase." end

    local out = {}
    table.insert(out, '{| class="wikitable sortable"')
    table.insert(out, "! Country !! Capital !! Population !! Founded !! Continent !! Wikibase")

    for _, row in ipairs(rows) do
        if type(row) == "table" and row.name then
            table.insert(out, "|-")
            table.insert(out,
                "| '''" .. (row.name or "") .. "'''"
                .. " || " .. (row.capital or "")
                .. " || " .. formatNumber(row.population)
                .. " || " .. (row.founded or "")
                .. " || " .. (row.continent or "")
                .. " || " .. wblink(row.item))
        end
    end

    table.insert(out, "|}")
    return table.concat(out, "\n")
end

function p.cities(frame)
    local query = [==[SELECT ?item ?itemLabel ?countryLabel ?population ?founded WHERE { ?item <https://wd.hxmn.dev/prop/direct/P1> <https://wd.hxmn.dev/entity/Q2> . ?item <http://www.w3.org/2000/01/rdf-schema#label> ?itemLabel . FILTER(LANG(?itemLabel) = 'en') OPTIONAL { ?item <https://wd.hxmn.dev/prop/direct/P2> ?country . ?country <http://www.w3.org/2000/01/rdf-schema#label> ?countryLabel . FILTER(LANG(?countryLabel) = 'en') } OPTIONAL { ?item <https://wd.hxmn.dev/prop/direct/P3> ?population . } OPTIONAL { ?item <https://wd.hxmn.dev/prop/direct/P4> ?founded . } } ORDER BY ?itemLabel]==]
    local fields = "item=$.results.bindings[*].item.value,name=$.results.bindings[*].itemLabel.value,country=$.results.bindings[*].countryLabel.value,population=$.results.bindings[*].population.value,founded=$.results.bindings[*].founded.value"

    local rows, err = sparql(query, fields)
    if err then return '<span class="error">SPARQL error: ' .. tostring(err) .. '</span>' end
    if not rows then return "No data returned from Wikibase." end

    local out = {}
    table.insert(out, '{| class="wikitable sortable"')
    table.insert(out, "! City !! Country !! Population !! Founded !! Wikibase")

    for _, row in ipairs(rows) do
        if type(row) == "table" and row.name then
            table.insert(out, "|-")
            table.insert(out,
                "| '''" .. (row.name or "") .. "'''"
                .. " || " .. (row.country or "")
                .. " || " .. formatNumber(row.population)
                .. " || " .. (row.founded or "")
                .. " || " .. wblink(row.item))
        end
    end

    table.insert(out, "|}")
    return table.concat(out, "\n")
end

return p