Module:Graph:Utils

Module documentation
local p = {}

function p.titleToJson(title)
	-- Load mediawiki page and decodes it as json
	local t = mw.title.new(title)
	if not t.exists then
		return nil
	else
		return mw.text.jsonDecode(t:getContent(), mw.text.JSON_TRY_FIXING)
	end
end

function p.recodeListToMap(frame)
	-- a function to re-code a json table in format [{},{},{}] to a map {},
	-- with each source object containing the same set of values, and the response
	-- mapping the "from" value to "to" value
	-- parameters: tbl, from, to
	local args = frame.args
	local tbl = p.titleToJson(args[1])
	local from = args[2]
	local to = args[3]
	local result = p.recodeListToMapFunc(tbl, from, to, args)
	return mw.text.jsonEncode(result)
end
 
function p.recodeListToMapFunc(tbl, from, to, values)
	-- a function to re-code a json table in format [{},{},{}] to a map {},
	-- with each source object containing the same set of values, and the response
	-- mapping the "from" values to "to" values
	-- parameters: tbl, from, to
	local dict = {}
	for k, v in pairs(tbl) do
		if v[from] ~= nil and v[to] ~= nil then
			dict[v[from]] = v[to]
		end
	end
	local result = {}
	for key, val in pairs(values) do
		if type(key) == "string" then
			local k = dict[key]
			if k ~= nil then
				result[k] = val
			end
		end
	end
	return result
end

function p.parseCsv(frame)
	local args = frame.args
	local content = mw.title.new(args[1]):getContent()
	local columnName = args[2]
	local result = p.parseCsvFunc(content, columnName)
	return mw.text.jsonEncode(result)
end

function p.parseCsvFunc(content, columnName)
	-- Simple, no escaping, csv parser. Assumes first row contains column names
	-- given csv text, extracts first column and names it 'id', and any other
	-- column that has the same name as the given columnName, and names it 'v'
	-- the result is in form:  [{id=...,v=...}, {id=...,v=...}], ...]
	-- if coulmn is not found, v= will not be given
	local result = {}
	local numberIdx = false

	for v in string.gmatch(content, '([^\n]*)') do
		local val = mw.text.trim(v)
		if val ~= '' then
			local parts = mw.text.split( val, ',', true )
			if numberIdx == false then
				numberIdx = true
				for i, v in ipairs(parts) do
					local val = mw.text.trim(v)
					if val == columnName then
						numberIdx = i
						break
					end
				end
			else
				local val = nil
				if numberIdx ~= true then
					val = tonumber(mw.text.trim(parts[numberIdx]))
				end
				table.insert(result, {
					id=mw.text.trim(parts[1]),
					v=val
				})
			end
		end
	end
	return result
end

function p.parseHCsv(frame)
	local args = frame.args
	local content = mw.title.new(args[1]):getContent()
	local rowId = args[2]
	local result = p.parseHCsvFunc(content, rowId)
	return mw.text.jsonEncode(result)
end

function p.parseHCsvFunc(content, id)
	-- Simple, no escaping, csv parser. Assumes first row contains column names
	-- given csv text, extracts just the row whos first column matches given id
	-- first column is not returned, all other column's headers become IDs
	-- the result is in form:  [{id=...,v=...}, {id=...,v=...}], ...]
	-- DEBUG:  =mw.text.jsonEncode(p.parseHCsvFunc('i,x,y,z\nb,1,2,3\na,2,3,4','a'))
	local result = {}
	local headers = false

	for v in string.gmatch(content, '([^\n]*)') do
		local val = mw.text.trim(v)
		if val ~= '' then
			local parts = mw.text.split( val, ',', true )
			if headers == false then
				headers = {}
				for i, v in ipairs(parts) do
					table.insert(headers, mw.text.trim(v))
				end
			elseif mw.text.trim(parts[1]) == id then
				local isFirst = true
				for i, v in ipairs(parts) do
					if isFirst then
						isFirst = false
					else
						table.insert(result, {
							id=headers[i],
							v=tonumber(mw.text.trim(v))
						})
					end
				end
				break
			end
		end
	end
	return result
end

function p.expandDict(frame)
	return mw.text.jsonEncode(p.expandDictFunc(mw.text.jsonDecode(frame.args[1])))
end

function p.expandDictFunc(inp)
	-- Converts compressed format json table to expanded format, for example:
	--    { "a": 10, "b": 20 }
	-- will be converted to 
	--    [{ "id": "a", "v": 10 }, { "id": "b", "v": 20 }]
	-- DEBUG:  =mw.text.jsonEncode(p.expandDictFunc(mw.text.jsonDecode('{ "a": 10, "b": 20 }')))
	local result = {}
	for k, v in pairs(inp) do
		table.insert(result, {
			id=k,
			v=v
		})
	end
	return result
end

return p