Fire Emblem Heroes Wiki
Advertisement
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

This wiki uses the Cargo extension for storing and querying data, acting essentially as a database. This allows for automated methods of creating some pages (eg. Lists), reducing the need for manual maintenance across several pages. A list of all Cargo tables can be found at Special:CargoTables.

Without Cargo, there might be the same information across multiple pages maintained manually (eg. Hero stats are used in multiple places). Previously, these pages needed to all be updated manually any time information changed. If all these pages instead use Cargo to grab the information from the Cargo table, we simply only need to change the information within the Cargo table. Then, all the pages pulling data from the Cargo table would pull the new values and automatically update accordingly.

Understanding templates

Cargo tables are declared and stored into via templates, so understanding Cargo also requires a basic understanding of how templates work. See the tutorial section for templates.

General overview

A simplification of Cargo is as follows:

  • Create/declare the Cargo table
  • Store information into the Cargo table
  • Query information from the Cargo table

The following sections will visit each topic more in-depth.

Declaring the Cargo table

To have a table to store information into, we must first create the table and also decide what kind of information we want stored in the table.

This is done inside the <noinclude></noinclude> tags in the template. For more details on what those tags do, see the MediaWiki article on Partial Transclusion, but in short, if we don't put the table declaration in those tags, the declare statement will be called wherever the template is called. We only want it called once on the Template page itself.

The tag for declaring the Cargo table is #cargo_declare. Inside the #cargo_declare, you will then specify:

  • Name of what you want to call the new table using _table=
  • Name and type (eg. Integer, String, Date, etc) of the columns you want to have in the table

Example

Here is the Cargo declaration from Template:Forging Bonds Infobox which stores information about Forging Bonds events.

{{#cargo_declare:
 _table=ForgingBonds
 |Name=String
 |Accessories=List (,) of Page
 |Number=Integer
 |StartTime=Start Datetime
 |EndTime=End Datetime
}}

In this #cargo_declare, the above:

  • Names the table ForgingBonds
  • Creates five parameters/columns to be in the table
    • Name - The name of an event.
      • This is type String, which is essentially just text. Any text will generally be accepted if a column is type String. These columns are indexed, while columns with type Text aren't.
    • Accessories - All the bonus Accessories in an event.
      • This is type List. This means it can store multiple values of the type specified after. In this case, List of Page (There can also be List of String, List of Datetime, etc.). The (,) represents the character(s) which separate each item in the list which in this case is a comma. Sample list input in this case would look like Feh Doll,Lance Røkkr Remnant,8-Bit Sharena. If we wanted to use another symbol, like a semicolon, we could change this to be List (;) of Page.
    • Number - A unique numerical index for each event.
      • This is type Integer. It can store 32-bit signed integers; fractional values, as well as integers that are too large (such as Voting Gauntlet scores), should use the type Float instead.
    • StartTime - The date and time an event starts on.
      • It has type Start Datetime so that only Datetime inputs can be accepted (eg. FEH Wiki won't be accepted as input to store into the table since it is not a datetime.)
    • EndTime - The date and time an event ends on.
      • It has type End Datetime, but accepts the same datetime values as Start Datetime. The datetime pair usually denotes the start and end times for a single row.

To create this table, you must first save the template and go to More > Recreate Data or add ?action=recreatedata to the end of the template URL. This option is only available to admins, so if you do not have the permission to create tables, contact an administrator. Every time the cargo_declare is modified, a table must be recreated for those changes to show up in the actual table.

After the table is created, go to Special:CargoTables to find the table. For this example, here is the ForgingBonds table with all the information we specified from the code snippet above.

Modifying the Cargo table

Storing information into the Cargo table

After you've created a new table, there won't be any rows of information yet in the table. To store information, we need to add #cargo_store tags into the template. These will go inside the <includeonly></includeonly> tags instead, so that information could get stored only when the template is transcluded in another page.

The #cargo_store follows a similar format where you:

  • Specify the table name to store info into
  • List out all the parameters/columns you want to store info into and the information you want to store.

Example

Here is the example #cargo_store for Template:Forging Bonds Infobox.

{{#cargo_store:
 _table=ForgingBonds
 |Name={{#if:{{{name|}}}|{{{name}}}|{{#titleparts:{{PAGENAME}}}}}}
 |Accessories={{{accessories|}}}
 |Number={{{number|}}}
 |StartTime={{{startTime|}}}
 |EndTime={{{endTime|}}}
}}

As mentioned, inside the #cargo_store we specify:

  • The name of the table we want to store into
    • In this case, ForgingBonds
  • All the parameters and what values we want to store into them.

This template stores the template parameters into each field. As a reminder, the triple curly bracket texts are template parameters passed in. The template parameters from the above code are:

  • {{{name|}}}
  • {{{accessories|}}}
  • {{{number|}}}
  • {{{startTime|}}}
  • {{{endTime|}}}

These are the parameters we specify when calling the template. The Forging Bonds infobox template actually has more than just these as template parameters such as characters, but these are the parameters we want stored into the Cargo table. The following is what a Forging Bonds infobox template call would look like, using the Wikicode from Harmony amid Chaos as the example.

{{Forging Bonds Infobox
|number=20
|characters=Ferdinand: Noblest of Nobles,Lysithea: Child Prodigy,Bernadetta: Eternal Loner,Annette: Overachiever
|accessories=Nomad Bandana EX,Spy Mask EX,Bard Torse EX,Wing-Leader Icon EX,Cavalier Cap,Bear Clip,Flytrap Doll,Melody Clip
|startTime=2020-03-06T07:00:00Z
|endTime=2020-03-20T07:00:00Z
}}

Cargo only cares about the parameters we told it to put into the table in the #cargo_store. The following table represents what would be stored into the table:

Column name Template parameter Value passed to #cargo_store
Name {{#if:{{{name|}}}|{{{name}}}|{{#titleparts:{{PAGENAME}}}}}} Harmony amid Chaos

Notes:

  • The #if function is used so that the name template parameter is passed only if it is non-empty. This is common in templates that expect editors to fill information into a blank boilerplate, so that an empty parameter like |name= wouldn't be used, instead {{#titleparts:{{PAGENAME}}}} will be used.
  • The #titleparts function is necessary because {{PAGENAME}} HTML-encodes certain entities, for example from ' into &#39;. If the latter is passed into the Cargo tables, other Cargo queries may not work properly.
Accessories {{{accessories|}}} Nomad Bandana EX,Spy Mask EX,Bard Torse EX,Wing-Leader Icon EX,Cavalier Cap,Bear Clip,Flytrap Doll,Melody Clip
Number {{{number|}}} 20
StartTime {{{startTime|}}} 2020-03-06T07:00:00Z
EndTime {{{endTime|}}} 2020-03-20T07:00:00Z

If you look up this banner in the Forging Bonds Cargo table, you can see that this is the information stored as well. You may notice that all tables have a _pageName column. This column is the page where a template call and the Cargo store happens. In this case, since we called the Forging Bonds infobox template from Harmony amid Chaos, the stored _pageName is also Harmony amid Chaos.

Preventing stores

In some cases, it is desirable to reuse a template in situations where Cargo tables must be kept intact, such as inside user pages. Some templates, such as {{Passive}}, allow this to be done using the no cargo parameter. (This is used on the Unused content page to display internal skills without affecting skill queries.) To add no cargo support to your template, the whole #cargo_store section needs to be surrounded inside a conditional statement as follows:

{{#if:{{{no cargo|}}}|<!--
// do not store anything if "no cargo" is specified
-->|<!--
// otherwise, proceed
-->{{#cargo_store:_table=<!-- -->}}<!--
// other stores go here
-->}}

Then, when a page transcludes the template while also supplying |no cargo=1 for the template arguments, no rows will be stored by the template.

Since only pages in the main namespace are expected to store rows into Cargo tables through templates, #cargo_stores should also be protected with a namespace check using {{#ifeq:{{NAMESPACE}}|{{ns:0}}| ... }}. This check is required for all Cargo table templates.

Other times, if a #cargo_store creates fields that would violate the constraints specified in the cargo_declare field descriptions, such as storing duplicate values on a unique column, the store silently fails and the corresponding row is not created.

Querying information from the Cargo tables

The information stored can now be queried anywhere from the Wiki with a the #cargo_query tag. There are also several other methods to query the Cargo tables (eg. #cargo_compound_query, via Lua using mw.ext.cargo.query), but this section will only cover doing a basic Cargo query. For more information on complex queries, refer to the Cargo documentation on querying data.

A basic #cargo_query expects:

  • The table name you want to query from

This is the only required information you need to specify to query the Cargo table, and it pulls every single row from the Cargo table. However, this isn't particularly useful. Other options you can include to narrow your search include:

  • fields - The columns you want to specify.
  • where - Condition you can specify to filter out results.
    • Conditions follow MYSQL syntax.
  • limit - The max number of results you want returned.
    • Defaults to 100 if not specified.
  • format - The format you want results to be returned in.
    • See Cargo documentation for a full list of formats you can return Cargo queries in.
  • order by - The order you want results to get returned in.

Although not documented on the MediaWiki Cargo page, REGEXP can also be used in place of = or LIKE.

Example

The following is an example #cargo_query which gets all pages and bonus Accessories of Forging Bonds events which started in 2019, ordered by their StartTime in ascending order in table format.

{{#cargo_query:
tables=ForgingBonds
|fields=_pageName,Accessories
|where=YEAR(StartTime)=2019
|format=table
|order by=StartTime ASC
}}

This code generates the following:

_pageName Accessories
Hearts as One Star of Nifl EX Crown of Nifl EX Frostflower Band EX Chilly Tiara EX Hawk Guard Heron Hairpin Heron Circlet Wolf Eyepatch
The Orb Case Hawk Guard EX Heron Hairpin EX Heron Circlet EX Wolf Eyepatch EX Worn-Out Doll Bird Nest Kitsune Ears Kitsune Doodad
Reason to Fight Worn-Out Doll EX Bird Nest EX Kitsune Ears EX Kitsune Doodad EX Dark Finery Kutolah Band Mage Cap Ilian Wing Hairpin
A Trust Earned Dark Finery EX Kutolah Band EX Mage Cap EX Ilian Wing Hairpin EX Symbol of Gallia Kitty Ribbon Beast Headband Forest Friends
Power's Den Symbol of Gallia EX Kitty Ribbon EX Beast Headband EX Forest Friends EX Winglet Hairpin Divine Tiara Nohrian Hairpin Wistful Hairpin
Spanning Time Winglet Hairpin EX Divine Tiara EX Nohrian Hairpin EX Wistful Hairpin EX Heart Charm Tinted Glasses False Taguel Ears Favored Helm
Joining Forces Heart Charm EX Tinted Glasses EX False Taguel Ears EX Favored Helm EX Academy Cap Deer Insignia Eagle Insignia Lion Insignia
Changing Winds Academy Cap EX Deer Insignia EX Eagle Insignia EX Lion Insignia EX Dire Notebook Quality Ribbon Handmade Clip Exotic Plume
A Time to Shine Dire Notebook EX Quality Ribbon EX Handmade Clip EX Exotic Plume EX Dancer's Ribbon Clover Hairpin Ethereal Tiara Concealing Mask
Common Virtues Dancer's Ribbon EX Clover Hairpin EX Ethereal Tiara EX Concealing Mask EX Falconine Helmet Saintly Ornament Knightly Helm Baronial Heaume
Mercenary Matters Falconine Helmet EX Saintly Ornament EX Knightly Helm EX Baronial Heaume EX Sage's Ornament Dancer's Frill Chief's Headband Renewal Charm
Path to the Future Sage's Ornament EX Dancer's Frill EX Chief's Headband Renewal Charm Astral Hairpin Mistress Band Axeman Bandana Archer Bandana

Styling Cargo query outputs

The above example table output is nice, but there are a few styling issues which could use some work. For example, the column names aren't exactly great header names for the table.

There are three main ways the FEH Wiki creates more complex formats to output in order of complexity. A few examples in the Wiki are included. To view the Cargo query code, view the source of those pages.

  • Using CONCAT() in |fields
  • Creating a template to use in the Cargo query via |format=template
  • Through Scribunto Lua modules
    • e.g. Template:Hero List and Module:HeroList
    • Lua runs much faster than Cargo queries, and a lot of complex data processing can be done in Lua while reducing the number of query calls
    • May also use CONCAT()
    • Queries via Lua do not translate to Cargo display formats directly, so Lua code must also generate the visual layout
    • Invoking the module without a wrapper template can roughly halve the post-expand include size
    • Not recommended for small templates frequently used in plain wikitext as #invoke adds visual noise

Allowed MySQL functions

These are the currently allowed functions on the wiki ($wgCargoAllowedSQLFunctions), non-default functions are bolded:

  • AVG
  • CEIL
  • CONCAT
  • COUNT
  • DATE
  • DATE_ADD
  • DATE_FORMAT
  • DATE_SUB
  • DATEDIFF
  • DAYOFMONTH
  • FLOOR
  • FORMAT
  • GROUP_CONCAT
  • IF
  • IFNULL
  • LCASE
  • LN
  • LOG
  • LOWER
  • MAX
  • MIN
  • MONTH
  • NEAR
  • NOW
  • POWER
  • ROUND
  • SUBSTRING
  • SUM
  • TRIM
  • UCASE
  • UPPER
  • YEAR

The following functions are not allowed, but their equivalent operators are available:

  • MOD → %
  • REGEXP_LIKE → REGEXP / RLIKE

Common fields on the wiki

  • |WikiName=String
This field is intended to uniquely identify a row where a page name is insufficient (because, for example, a page may store multiple distinct objects into the same table where all rows need to be distinguished in joins). These fields are often parsed through Template:MF for filename use for example. WikiName fields should not contain any symbols or Unicode characters to avoid technological issues. WikiName fields are for internal use only, and terminology guidelines should still be followed when actually displaying names. All WikiName fields should add the mandatory and unique constraints.
  • |TagID=String
This field represents the internal string identifier of a row in the game assets. The main purpose of including them in the Cargo database is to allow external scripts to map game entities to wiki page names efficiently. They should not be used in queries for wiki content, but can be freely used in code that generates wikitext from game files, e,g, Module:ScenarioArchiveToWiki. All TagID fields should add the unique constraint, but not mandatory since rows may be created after new information is released but before game files are available through updates.
  • |Properties=List (,) of String
This field represents an unordered set of properties that apply to a given row. If a property is called abc, the presence of a property can be checked with the following where-clauses:
  • Properties HOLDS 'abc'; Cargo internally translates this to TABLE__Properties._value='abc' with a suitable join, and at most one HOLDS statement can be used on each table.
  • Properties__full LIKE '%abc%'; because of this, properties must not be substrings of other properties, to prevent false positives.
The opposite can be checked with the following where-clauses:
  • Properties__full IS NULL OR Properties__full NOT LIKE '%abc%'
  • IFNULL(Properties__full,'') NOT LIKE '%abc%'
The HOLDS NOT command is not a negation of the HOLDS command; it returns true if the row contains any property that is not equal to abc. The HOLDS commands cannot be used as predicates inside the IF() function as they are purely Cargo extensions.
  • |StartTime=Start Datetime, |EndTime=End Datetime
These fields mark a UTC datetime range, and usually represent the time availability of an object. Both datetimes are inclusive; a time point x is included if x BETWEEN StartTime AND EndTime, or x>=StartTime AND x<=EndTime. To simplify queries, it is permissible to store {{MinTime}} and {{MaxTime}} respectively into rows without explicit start or end times, but only if the null value does not have a special meaning.
Advertisement