Module:GetData: Difference between revisions

From Bodhicitta
((by SublimeText.Mediawiker))
(VSCode edit)
 
(133 intermediate revisions by the same user not shown)
Line 5: Line 5:
     local prop = frame:getParent().args[1]
     local prop = frame:getParent().args[1]
     local source = frame.args.source
     local source = frame.args.source
     if source then
     local title = mw.title.getCurrentTitle().subpageText
        return source
 
     end
    local queryPart = "[[" .. title .. "]]|?" .. prop .. "#|limit=1|valuesep=;|sep=;"
    local encodedQuery = mw.uri.encode(queryPart)
    local queryUrl = "https://" .. source .. ".tsadra.org/api.php?action=ask&api_version=3&format=json&query=" .. encodedQuery
    -- if queryUrl then
    --    return queryUrl
     -- end
    local data, errors = mw.ext.externalData.getExternalData(queryUrl)


    local extQuery = mw.uri.encode( "[[" .. mw.title.getCurrentTitle().subpageText .. "]]|?" .. prop .. "#|limit=1|valuesep=;|sep=;" )
     local json = not errors and data.__json or false
    local remoteContent, rcErrors = mw.ext.externalData.getExternalData("https://" .. source .. ".tsadra.org/api.php?action=ask&query=" .. extQuery .. "&format=json&api_version=3")
     local json = not rcErrors and remoteContent.__json or false


     if #json then
     if #json then
Line 17: Line 21:
             for name, values in pairs (result) do
             for name, values in pairs (result) do
                 for prop, value in pairs (values.printouts) do
                 for prop, value in pairs (values.printouts) do
                     return value
                    local dataOutput = value
                    if type( value ) == 'table' then
                        local flat = {}
                        for _, item in ipairs( value ) do
                            if type( item ) == 'table' then
                                table.insert( flat, item.fulltext or item.label or tostring( item ) )
                            else
                                table.insert( flat, tostring( item ) )
                            end
                        end
                        dataOutput = table.concat( flat, '; ')
                    end
                     return dataOutput
                 end
                 end
             end
             end
Line 26: Line 42:


end
end
function p.remoteGetNonApi(frame)
    local prop = frame:getParent().args[1]
    local source = frame.args.source
    local title = mw.uri.encode( mw.title.getCurrentTitle().subpageText )
    local queryUrl = 'https://' .. source .. '.tsadra.org/index.php?title=Special%3AAsk&q=%5B%5B' .. title .. '%5D%5D&po=' .. prop .. '&p%5Blimit%5D=1&p%5Bformat%5D=csv&p%5Bvaluesep%5D=;'
    -- if queryUrl then
    --    return queryUrl
    -- end
    local data = mw.ext.externalData.getExternalData{
        url = queryUrl ,
        data = {
            Value = prop
        } ,
        format = 'CSV with header'
    }
    if data then
        return queryUrl .. '<br><br>' .. data.Value
    else
        return 'No data! ¯\\_(ツ)_/¯'
    end
end


function p.remoteSet(frame)
function p.remoteSet(frame)


     local pargs = frame:getParent().args
     local pargs = frame:getParent().args
if pargs.page then
pagename = pargs.page
else
pagename = mw.title.getCurrentTitle().subpageText
end


     local properties = ''
     local properties = ''
Line 36: Line 86:
     end
     end


     local extQuery = mw.uri.encode( "[[" .. mw.title.getCurrentTitle().subpageText .. "]]" .. properties .. "|limit=10000|valuesep=;|sep=;" )
     local extQuery = mw.uri.encode( "[[" .. pagename .. "]]" .. properties .. "|limit=10000|valuesep=;|sep=;" )


     -- local testQuery = "https://" .. pargs.source .. ".tsadra.org/api.php?action=ask&query=" .. extQuery .. "&format=json&api_version=3"
     -- local testQuery = "https://" .. pargs.source .. ".tsadra.org/api.php?action=ask&query=" .. extQuery .. "&format=json&api_version=3"
Line 46: Line 96:
     local json = not rcErrors and remoteContent.__json or false
     local json = not rcErrors and remoteContent.__json or false


     -- EXAMPLE: https://commons.tsadra.org/api.php?action=ask&query=%5B%5BRhoton%2C+J.%5D%5D%7C%3FFirstImage%7C%3FMainNamePhon%7Climit%3D10000&format=json&api_version=3
    if rcErrors then
        return rcErrors
    end
     -- EXAMPLE: https://research.tsadra.org/api.php?action=ask&query=%5B%5BRhoton%2C+J.%5D%5D%7C%3FFirstImage%7C%3FMainNamePhon%7Climit%3D10000&format=json&api_version=3
 
    -- Properties listed in |multi= are multi-valued: they get a '+sep=' directive so
    -- SMW splits the stored string into separate values. Without |multi=, |sep= applies
    -- to every property in the batch (legacy behaviour, kept for existing callers).
    -- |multi= is what lets one call handle both single- and multi-valued properties,
    -- instead of splitting into two calls (= two remote HTTP fetches).
    local multiProps = {}
    if pargs.multi then
        for value in string.gmatch(pargs.multi, "([^;]+)") do
            multiProps[ mw.text.trim( value ) ] = true
        end
    end
 
    local separator = pargs.sep or ';'


     local dataStore = {}
     local dataStore = {}
Line 56: Line 123:
                     local dataOutput = value
                     local dataOutput = value
                     if type( value ) == 'table' then
                     if type( value ) == 'table' then
                         dataOutput = mw.text.listToText( value, '; ')
                        local flat = {}
                        for _, item in ipairs( value ) do
                            if type( item ) == 'table' then
                                table.insert( flat, item.fulltext or item.label or tostring( item ) )
                            else
                                table.insert( flat, tostring( item ) )
                            end
                        end
                         dataOutput = table.concat( flat, '; ')
                     end
                     end
                     table.insert(dataStore, prop .. '=' .. dataOutput)
                     table.insert(dataStore, prop .. '=' .. dataOutput)
                     if pargs.sep then
                     if pargs.multi then
                        -- Only flag the properties explicitly declared multi-valued.
                        if multiProps[prop] then
                            table.insert(dataStore, '+sep=' .. separator)
                        end
                    elseif pargs.sep then
                        -- Legacy: no |multi= given, so |sep= applies to the whole batch.
                         table.insert(dataStore, '+sep=' .. pargs.sep)
                         table.insert(dataStore, '+sep=' .. pargs.sep)
                     end
                     end
Line 84: Line 165:
     end
     end


local pSetData = mw.loadData('Module:GetData/'..frame.args['data'])
    local pSetData = mw.loadData('Module:GetData/'..frame.args['data'])
local parentArgs = frame:getParent().args
    local parentArgs = frame:getParent().args


     local props = ''
     local props = ''
Line 97: Line 178:


     for propValue in string.gmatch(props, "([^;]+)") do
     for propValue in string.gmatch(props, "([^;]+)") do
    if propValue and pSetData[propValue] then  
        if propValue and pSetData[propValue] then  
             table.insert(dataStore, propValue .. '=' .. pSetData[propValue])
             table.insert(dataStore, propValue .. '=' .. pSetData[propValue])
             if parentArgs.sep then
             if parentArgs.sep then
            table.insert(dataStore, '+sep=' .. parentArgs.sep)
                table.insert(dataStore, '+sep=' .. parentArgs.sep)
             end
             end
         end
         end
     end
     end


local dataStored = mw.smw.set( dataStore )
    local dataStored = mw.smw.set( dataStore )


     if dataStored == true then
     if dataStored == true then
Line 114: Line 195:


end
end
function p.remoteGetCategory(frame)
    local category = frame.args.category or "Terms"
    local source = frame.args.source or "commons"
    local limit = frame.args.limit or "1000"
    local nocache = frame.args.nocache
    local queryPart = "[[Category:" .. category .. "]]|limit=" .. limit
    local encodedQuery = mw.uri.encode(queryPart)
    local queryUrl = "https://" .. source .. ".tsadra.org/api.php?action=ask&api_version=3&format=json&query=" .. encodedQuery
    if nocache then
        queryUrl = queryUrl .. "&nocache=" .. os.time()
    end
    local data, errors = mw.ext.externalData.getExternalData(queryUrl)
    if errors or not data then
        return 'fetch error'
    end
    local titles = {}
    for i = 1, data.count do
        local row = data[i]
        if type(row) == 'table' and row.fulltext then
            table.insert(titles, row.fulltext)
        end
    end
    return table.concat(titles, ";")
end


function p.main(frame)
function p.main(frame)


     -- bringing in property values from the appropriate set for this item
     -- bringing in property values from the appropriate set for this item
local pData = mw.loadData('Module:GetData/'..frame.args['data'])
    local pData = mw.loadData('Module:GetData/'..frame.args['data'])


     -- bringing in the arguments passed to the parent templates
     -- bringing in the arguments passed to the parent templates
local parentArgs = frame:getParent().args
    local parentArgs = frame:getParent().args


     -- bringing in the properties being requested and feeding into a table
     -- bringing in the properties being requested and feeding into a table
Line 179: Line 293:
                 pdString = ""
                 pdString = ""
                 for k,v in pairs(pdTable) do
                 for k,v in pairs(pdTable) do
                     if v then
                     if v and tostring(v) then
                         mapdVal = string.gsub(map, "@@@", v)
                         mapdVal = string.gsub(map, "@@@", v)
                         pdString = pdString .. mapdVal
                         pdString = pdString .. mapdVal
Line 188: Line 302:
             -- checking if a printsep parameter has been defined and separating each mapped value accordingly
             -- checking if a printsep parameter has been defined and separating each mapped value accordingly
             if parentArgs.printsep then
             if parentArgs.printsep then
            finalString = finalString .. parentArgs.printsep .. frame:preprocess( pdString )
                finalString = finalString .. parentArgs.printsep .. frame:preprocess( pdString )
            if mw.ustring.sub(finalString, 1, 1) == parentArgs.printsep then
                if mw.ustring.sub(finalString, 1, 1) == parentArgs.printsep then
finalString = mw.ustring.sub(finalString, 2)
                    finalString = mw.ustring.sub(finalString, 2)
end
                end
             else
             else
            finalString = finalString .. frame:preprocess( pdString )
                finalString = finalString .. frame:preprocess( pdString )
             end
             end
         end
         end
Line 209: Line 323:
     -- checking if a silent flag has been added, if so and string is empty anyways, return string, otherwise, check for default parent argument and return that.
     -- checking if a silent flag has been added, if so and string is empty anyways, return string, otherwise, check for default parent argument and return that.
     if parentArgs.silent ~= "yes" then
     if parentArgs.silent ~= "yes" then
    if finalString ~= "" and finalString ~= nil then
        if finalString ~= "" and finalString ~= nil then
        return finalString
            return finalString
    else
        else
    if parentArgs.default then
            if parentArgs.default then
    return parentArgs.default
                return parentArgs.default
    end
            end
    end
        end
end
    end
end
end


return p
return p

Latest revision as of 15:43, 13 August 2026

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

local p = {}

function p.remoteGet(frame)

    local prop = frame:getParent().args[1]
    local source = frame.args.source
    local title = mw.title.getCurrentTitle().subpageText

    local queryPart = "[[" .. title .. "]]|?" .. prop .. "#|limit=1|valuesep=;|sep=;"
    local encodedQuery = mw.uri.encode(queryPart)
    local queryUrl = "https://" .. source .. ".tsadra.org/api.php?action=ask&api_version=3&format=json&query=" .. encodedQuery
    -- if queryUrl then
    --     return queryUrl
    -- end
    local data, errors = mw.ext.externalData.getExternalData(queryUrl)

    local json = not errors and data.__json or false

    if #json then
        for _, result in ipairs(json.query.results) do
            for name, values in pairs (result) do
                for prop, value in pairs (values.printouts) do
                    local dataOutput = value
                    if type( value ) == 'table' then
                        local flat = {}
                        for _, item in ipairs( value ) do
                            if type( item ) == 'table' then
                                table.insert( flat, item.fulltext or item.label or tostring( item ) )
                            else
                                table.insert( flat, tostring( item ) )
                            end
                        end
                        dataOutput = table.concat( flat, '; ')
                    end
                    return dataOutput
                end
            end
        end
    else
        return 'No data! ¯\\_(ツ)_/¯'
    end

end


function p.remoteGetNonApi(frame)

    local prop = frame:getParent().args[1]
    local source = frame.args.source
    local title = mw.uri.encode( mw.title.getCurrentTitle().subpageText )

    local queryUrl = 'https://' .. source .. '.tsadra.org/index.php?title=Special%3AAsk&q=%5B%5B' .. title .. '%5D%5D&po=' .. prop .. '&p%5Blimit%5D=1&p%5Bformat%5D=csv&p%5Bvaluesep%5D=;'
    -- if queryUrl then
    --     return queryUrl
    -- end
    local data = mw.ext.externalData.getExternalData{
        url = queryUrl ,
        data = {
            Value = prop
        } ,
        format = 'CSV with header'
    }

    if data then
        return queryUrl .. '<br><br>' .. data.Value
    else
        return 'No data! ¯\\_(ツ)_/¯'
    end

end



function p.remoteSet(frame)

    local pargs = frame:getParent().args
	if pargs.page then
		pagename = pargs.page
	else
		pagename = mw.title.getCurrentTitle().subpageText
	end

    local properties = ''
    for value in string.gmatch(pargs.props, "([^;]+)") do
        properties = properties .. "|?" .. value .. "#"
    end

    local extQuery = mw.uri.encode( "[[" .. pagename .. "]]" .. properties .. "|limit=10000|valuesep=;|sep=;" )

    -- local testQuery = "https://" .. pargs.source .. ".tsadra.org/api.php?action=ask&query=" .. extQuery .. "&format=json&api_version=3"
    -- if testQuery then
    --     return testQuery
    -- end

    local remoteContent, rcErrors = mw.ext.externalData.getExternalData("https://" .. pargs.source .. ".tsadra.org/api.php?action=ask&query=" .. extQuery .. "&format=json&api_version=3")
    local json = not rcErrors and remoteContent.__json or false

    if rcErrors then
        return rcErrors
    end
    -- EXAMPLE: https://research.tsadra.org/api.php?action=ask&query=%5B%5BRhoton%2C+J.%5D%5D%7C%3FFirstImage%7C%3FMainNamePhon%7Climit%3D10000&format=json&api_version=3

    -- Properties listed in |multi= are multi-valued: they get a '+sep=' directive so
    -- SMW splits the stored string into separate values. Without |multi=, |sep= applies
    -- to every property in the batch (legacy behaviour, kept for existing callers).
    -- |multi= is what lets one call handle both single- and multi-valued properties,
    -- instead of splitting into two calls (= two remote HTTP fetches).
    local multiProps = {}
    if pargs.multi then
        for value in string.gmatch(pargs.multi, "([^;]+)") do
            multiProps[ mw.text.trim( value ) ] = true
        end
    end

    local separator = pargs.sep or ';'

    local dataStore = {}

    if #json then
        for _, result in ipairs(json.query.results) do
            for name, values in pairs (result) do
                for prop, value in pairs (values.printouts) do
                    local dataOutput = value
                    if type( value ) == 'table' then
                        local flat = {}
                        for _, item in ipairs( value ) do
                            if type( item ) == 'table' then
                                table.insert( flat, item.fulltext or item.label or tostring( item ) )
                            else
                                table.insert( flat, tostring( item ) )
                            end
                        end
                        dataOutput = table.concat( flat, '; ')
                    end
                    table.insert(dataStore, prop .. '=' .. dataOutput)
                    if pargs.multi then
                        -- Only flag the properties explicitly declared multi-valued.
                        if multiProps[prop] then
                            table.insert(dataStore, '+sep=' .. separator)
                        end
                    elseif pargs.sep then
                        -- Legacy: no |multi= given, so |sep= applies to the whole batch.
                        table.insert(dataStore, '+sep=' .. pargs.sep)
                    end
                end
            end
        end
    end

    local dataStored = mw.smw.set( dataStore )

    if dataStored == true then
        return ''
    else
        return 'An error occurred during the storage process. Message reads ' .. dataStored.error
    end

end


function p.set(frame)

    if not mw.smw then
        return "mw.smw module not found"
    end

    local pSetData = mw.loadData('Module:GetData/'..frame.args['data'])
    local parentArgs = frame:getParent().args

    local props = ''
    if parentArgs.props then
        props = parentArgs.props
    else
        props = parentArgs.prop
    end
    
    local dataStore = {}

    for propValue in string.gmatch(props, "([^;]+)") do
        if propValue and pSetData[propValue] then 
            table.insert(dataStore, propValue .. '=' .. pSetData[propValue])
            if parentArgs.sep then
                table.insert(dataStore, '+sep=' .. parentArgs.sep)
            end
        end
    end

    local dataStored = mw.smw.set( dataStore )

    if dataStored == true then
        return ''
    else
        return 'An error occurred during the storage process. Message reads ' .. dataStored.error
    end

end

function p.remoteGetCategory(frame)

    local category = frame.args.category or "Terms"
    local source = frame.args.source or "commons"
    local limit = frame.args.limit or "1000"

    local nocache = frame.args.nocache

    local queryPart = "[[Category:" .. category .. "]]|limit=" .. limit
    local encodedQuery = mw.uri.encode(queryPart)
    local queryUrl = "https://" .. source .. ".tsadra.org/api.php?action=ask&api_version=3&format=json&query=" .. encodedQuery
    if nocache then
        queryUrl = queryUrl .. "&nocache=" .. os.time()
    end

    local data, errors = mw.ext.externalData.getExternalData(queryUrl)

    if errors or not data then
        return 'fetch error'
    end

    local titles = {}
    for i = 1, data.count do
        local row = data[i]
        if type(row) == 'table' and row.fulltext then
            table.insert(titles, row.fulltext)
        end
    end
    return table.concat(titles, ";")

end


function p.main(frame)

    -- bringing in property values from the appropriate set for this item
    local pData = mw.loadData('Module:GetData/'..frame.args['data'])

    -- bringing in the arguments passed to the parent templates
    local parentArgs = frame:getParent().args

    -- bringing in the properties being requested and feeding into a table
    local props = parentArgs.prop
    local propTable = {}
    for propValue in string.gmatch(props, "([^;]+)") do
        table.insert(propTable, propValue)
    end

    -- checking if a single property called actually has a value, if not return nothing
    if #propTable == 1 then
        local valueCheck = propTable[1]
        if pData[valueCheck] == '' or pData[valueCheck] == nil then 
            if parentArgs.default then
                return parentArgs.default
            else
                return ''
            end
        end
    end

    -- defining our output variable
    local finalString = ""

    -- if an intro string has been defined, adding to output string now
    if parentArgs.intro then
        for k,v in ipairs(propTable) do
            if pData[v] ~= "" then
                finalString = parentArgs.intro
            end
        end
    end

    -- iterating through requested properties
    for i,prop in pairs(propTable) do
        if pData[prop] then

            -- feeding property value into a variable
            local pdString = pData[prop]

            -- checing if a "map" parameter has been defined
            if parentArgs.map then
                local pdTable = {}

                -- checking if a sep parameter has been defined and splitting values accordingly
                if parentArgs.sep then
                    local sep = parentArgs.sep
                    for value in string.gmatch(pdString, "([^" .. sep .. "]+)") do
                        table.insert(pdTable, value)
                    end
                else
                    table.insert(pdTable, pdString)
                end

                -- mapping each value from above
                local map = parentArgs.map
                pdString = ""
                for k,v in pairs(pdTable) do
                    if v and tostring(v) then
                        mapdVal = string.gsub(map, "@@@", v)
                        pdString = pdString .. mapdVal
                    end
                end
            end

            -- checking if a printsep parameter has been defined and separating each mapped value accordingly
            if parentArgs.printsep then
                finalString = finalString .. parentArgs.printsep .. frame:preprocess( pdString )
                if mw.ustring.sub(finalString, 1, 1) == parentArgs.printsep then
                    finalString = mw.ustring.sub(finalString, 2)
                end
            else
                finalString = finalString .. frame:preprocess( pdString )
            end
        end
    end

    -- if an outro string has been defined, adding to output string now
    if parentArgs.outro then
        for k,v in ipairs(propTable) do
            if pData[v] ~= "" then
                finalString = finalString .. parentArgs.outro
            end
        end
    end

    -- checking if a silent flag has been added, if so and string is empty anyways, return string, otherwise, check for default parent argument and return that.
    if parentArgs.silent ~= "yes" then
        if finalString ~= "" and finalString ~= nil then
            return finalString
        else
            if parentArgs.default then
                return parentArgs.default
            end
        end
    end
end

return p