Module:NeoWikiDemo: Difference between revisions

Content deleted Content added
NeoWiki (talk | contribs)
Importing NeoWiki demo data
NeoWiki (talk | contribs)
Importing NeoWiki demo data
 
(3 intermediate revisions by the same user not shown)
Line 62:
end
rows[#rows + 1] = '|-'
rows[#rows + 1] = '| ' .. name .. ' || ' .. stmt.typepropertyType .. ' || ' .. table.concat( vals, ', ' )
end
 
Line 85:
end
 
local function renderRowsAsTable( rows, columns, linkColumns )
if #rows == 0 then
return 'No results'
Line 96:
end
table.sort( columns )
end
 
local linkSet = {}
if linkColumns then
for _, col in ipairs( linkColumns ) do
linkSet[col] = true
end
end
 
Line 104 ⟶ 111:
for _, col in ipairs( columns ) do
local v = row[col]
cells[#cellslocal + 1]cell = v == nil and '' or tostring( v )
if linkSet[col] and cell ~= '' then
cell = '[[' .. cell .. ']]'
end
cells[#cells + 1] = cell
end
out[#out + 1] = '|-'
Line 115 ⟶ 126:
 
function p.query( frame )
local columns = nil
return renderRowsAsTable( nw.query( frame.args[1] ) )
if frame.args.columns then
columns = mw.text.split( frame.args.columns, ',%s*' )
end
 
local linkColumns = nil
if frame.args.linkColumns then
linkColumns = mw.text.split( frame.args.linkColumns, ',%s*' )
end
 
return renderRowsAsTable( nw.query( frame.args[1] ), columns, linkColumns )
end
 
local function statementValue( stmt )
if not stmt or not stmt.values or stmt.values[1] == nil then
return nil
end
local v = stmt.values[1]
if type( v ) == 'table' then
return v.label or v.target
end
return v
end
 
-- Renders a wikitable from the current page's child Subjects.
-- Args: columns=Col1, Col2 (required, in order)
-- schema=SchemaName (optional, filters children to one schema)
-- sortBy=ColName (optional)
-- sortDir=asc|desc (optional, default desc)
-- numberColumns=Col1, Col2 (optional, formatted with thousand separators)
function p.childTable( frame )
local columns = mw.text.split( frame.args.columns or '', ',%s*' )
local schemaFilter = frame.args.schema
local sortBy = frame.args.sortBy
local sortDir = frame.args.sortDir or 'desc'
 
local numberSet = {}
if frame.args.numberColumns then
for _, col in ipairs( mw.text.split( frame.args.numberColumns, ',%s*' ) ) do
numberSet[col] = true
end
end
 
local children = nw.getChildSubjects()
if not children then
return ''
end
 
local lang = mw.getContentLanguage()
local rows = {}
 
for _, child in ipairs( children ) do
if not schemaFilter or child.schema == schemaFilter then
local row = {}
for _, col in ipairs( columns ) do
local v = statementValue( child.statements[col] )
if v == nil then
row[col] = ''
elseif numberSet[col] and tonumber( v ) then
row[col] = lang:formatNum( tonumber( v ) )
else
row[col] = tostring( v )
end
end
-- Stash the raw sort value so number columns sort numerically
-- even after thousand-separator formatting has stringified them.
if sortBy then
row.__sortValue = statementValue( child.statements[sortBy] )
end
rows[#rows + 1] = row
end
end
 
if sortBy then
table.sort( rows, function( a, b )
local av, bv = a.__sortValue, b.__sortValue
local an, bn = tonumber( av ), tonumber( bv )
if an and bn then
if sortDir == 'asc' then return an < bn end
return an > bn
end
if sortDir == 'asc' then return tostring( av ) < tostring( bv ) end
return tostring( av ) > tostring( bv )
end )
end
 
return renderRowsAsTable( rows, columns, nil )
end
 
Line 180 ⟶ 277:
 
return renderRowsAsTable( rows, { 'Name', 'Type', 'Required', 'Details' } )
end
 
local PERSON_EVENTS_MONTHS = {
'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'
}
 
-- Formats an ISO yyyy-mm-dd string as "21 March 1685" without relying on
-- MediaWiki's date parsing, which is unreliable for pre-modern years.
local function personEventsFormatDate( iso )
local y, m, d = string.match( iso or '', '^(%d+)-(%d+)-(%d+)$' )
if not y then
return iso or ''
end
return tonumber( d ) .. ' ' .. ( PERSON_EVENTS_MONTHS[tonumber( m )] or m ) .. ' ' .. y
end
 
local PERSON_EVENTS_ROLES = {
['Brought into life'] = 'Born',
['By mother'] = 'Mother',
['From father'] = 'Father',
}
 
-- Renders the current Person page's life events as a table by reverse-querying
-- the graph: the canonical edges run Birth -> Person, so a person's role in each
-- event ("was born" / CIDOC P98i, mother, father) is derived here rather than
-- stored as an inverse edge. The `date` property is stored as a native Neo4j
-- date list; the result normalizer renders b.Date[0] as a Y-m-d string.
function p.personEvents( frame )
local name = mw.title.getCurrentTitle().text
 
local events = nw.query(
'MATCH (b:Birth)-[r]->(p:Person {name: $name}) ' ..
'OPTIONAL MATCH (b)-[:`Took place at`]->(pl:Place) ' ..
'RETURN type(r) AS role, b.name AS event, b.Date[0] AS date, pl.name AS place ORDER BY date',
{ name = name }
)
 
if not events or #events == 0 then
return ''
end
 
local rows = {}
for _, e in ipairs( events ) do
rows[#rows + 1] = {
Role = PERSON_EVENTS_ROLES[e.role] or e.role,
Event = e.event,
Date = e.date and personEventsFormatDate( e.date ) or '',
Place = e.place or '',
}
end
 
return "'''Life events'''\n" .. renderRowsAsTable( rows, { 'Role', 'Event', 'Date', 'Place' }, { 'Event', 'Place' } )
end