Extension:Cargo/Querying data

Querying of data within Cargo is done via two functions: #cargo_query and #cargo_compound_query. The latter function essentially calls two or more queries at the same time, then displays their results together.

#cargo_query
The #cargo_query function is essentially a wrapper around SQL, with a few modifications. It is called with the following syntax:

The first seven parameters should look fairly familiar to anyone experienced with SQL SELECT queries:
 * "tables=" corresponds to the FROM clause; "table" is an alias for it.
 * "join on=" corresponds to the JOIN...ON clauses.
 * "fields=" corresponds to the SELECT clause (with the optional "alias" values corresponding to AS clauses). Its default value is "_pageName".
 * "where=" corresponds to the WHERE clause.
 * "order by=" corresponds to the ORDER BY clause. Its default values is "_pageName ASC".
 * "group by=" corresponds to the GROUP BY clause.
 * "limit=" corresponds to the LIMIT clause.

The next three parameters are conditional, being applied depending on whether or not there are results:
 * "intro=" - sets text that goes right before the query results; applied only if there are results.
 * "outro=" - sets text that goes right after the query results; applied only if there are results.
 * "default=" - sets text that goes in place of the query results, if there are no results. The default value is "No results", in the language of the user. To not have any text appear, just set "default=".

Finally, there is the "format=" parameter, and any parameters specific to that format. See "Display formats" below for the possible values for these.

Of all these parameters, "tables=" is the only required one; although if "tables=" holds multiple tables, "join on=" is required as well.

Examples
The following query gets all the cities on the current (fictional) wiki and their populations, and displays them in a table:

The following query gets only cities in Asia, and displays the city name, the country name and the population, all in a dynamic, JavaScript-based table:

The following query gets all countries in the wiki, and the number of cities in each one that have a page in the wiki, and displays the set of numbers with a bar chart, with the highest number of cities at the beginning:

#cargo_compound_query
You may want to have the results of more than one query within the same display; this is possible using the #cargo_compound_query function. The main usage for such "compound queries" is to display multiple sets of points on a map or calendar, with a different icon (in maps) or a different color (in calendars) for each set; though it's also possible to use it to show multiple result sets within simpler formats like tables and lists.


 * 1) cargo_compound_query is called by passing in the sets of parameters of one or more calls to #cargo_query, with the overall sets separated by pipes, and the internal parameters now separated by semicolons.

Here is an example call, that would show two groups of pages in a map, with a different icon for each:

Display formats
The "format=" parameter lets you set in which format to display the results. The Cargo extension supports the following formats:

Lists

 * list: Displays results in a delimited list.
 * Parameters:
 * delimiter - sets the separator character (default is comma)


 * ul: Displays results in a bulleted list.
 * Parameters:
 * columns - sets the number of columns (default is 1)


 * ol: Displays results in a numbered list.
 * Parameters:
 * columns - sets the number of columns (default is 1)


 * category: Displays results in the style of MediaWiki categories.
 * Parameters:
 * columns - sets the number of columns (default is 3)

More complex text displays

 * template</tt>: Displays results using a MediaWiki template that formats each row of results. The template in question must use unnamed parameters, i.e. it must refer to its parameters as, etc.
 * Parameters:
 * template</tt> - specifies the name of the template to use (mandatory)


 * embedded</tt>: Shows the full text of each queried page (only the first field of the query is used). (No parameters.)


 * outline</tt>: Shows results in an outline format.
 * Parameters:
 * outline fields</tt> - holds a comma-separated list of the query's fields; these fields are used to define the outline, by which the results are grouped together (mandatory)


 * tree</tt>: Shows results in a tree format, in which a single field defines all the relationships between "child" pages and "parent" pages.
 * Parameters:
 * parent field</tt> - holds the name of this connector field (mandatory)


 * table</tt>: Displays results in a table. (No parameters.)


 * dynamic table</tt>: Displays results in a "dynamic" table that includes sorting, pagination and searching, using the DataTables JavaScript library. (No parameters.)

Time-based displays

 * calendar</tt>: Displays results in a calendar, using the FullCalendar JavaScript library.
 * Parameters:
 * width</tt> - sets the width of the calendar (default is 100%)
 * start date</tt> - sets the date at which to display the calendar (default is the current date)
 * color</tt> - sets the color in which to show the names of events; useful within #compound_query (default is set by the FullCalendar library)


 * timeline</tt>: Displays results in a timeline, using the SIMILE Timeline library.
 * Parameters:
 * height</tt> - sets the height of the timeline (default is 350px)
 * width</tt> - sets the width of the timeline (default is 100%)

Numerical displays

 * <tt>bar chart</tt>: Displays results in a bar chart (with horizontal bars), using the NVD3 JavaScript library.
 * Parameters:
 * <tt>height</tt> - sets the height of the bar chart (default is based on the number of bars)
 * <tt>width</tt> - sets the width of the bar chart (default is 100%)

Maps

 * <tt>googlemaps</tt>: Displays results in a map, using the Google Maps service.
 * Parameters:
 * <tt>height</tt> - sets the height of the map (default is 400px)
 * <tt>width</tt> - sets the width of the map (default is 700px)
 * <tt>icon</tt> - sets a custom icon to be used to display points; value must be the name of a file that has been uploaded to the wiki. This is especially useful within #compound_query.
 * <tt>zoom</tt> - sets the zoom level, i.e. an integer value from around 0 to around 20, with higher numbers being more zoomed in (default is based on the area of the set of points being displayed).


 * <tt>openlayers</tt>: Displays results in a map, using the OpenLayers service.
 * Parameters: same as for <tt>googlemaps</tt>.

Additionally, two export-based display formats are defined: <tt>csv</tt> and <tt>json</tt>; see Exporting data.

If no format is specified, <tt>list</tt> is the default format if there is only a single field being displayed in the results, while <tt>table</tt> is the default format if there is more than one field.

The "HOLDS" command
SQL's own support for fields that contain lists/arrays is unfortunately rather poor. For this reason, #cargo_declare creates an additional, helper table for each field that holds a list of values. Additionally, #cargo_query supports a new, SQL-like command, "HOLDS", within the "join on=" and "where=" parameters, that makes querying on such data easier. Instead of having to manually include the helper table in each such call, you can use "HOLDS" to simplify the syntax; it is what is known as "syntactic sugar" for the true, more complex, SQL.

You can use "HOLDS" within the "where=" parameter to find all rows whose list field contains a certain value. To use our earlier example, if we have a table called "Books" that contains a field, "Authors", holding a list of authors, we can use the following #cargo_query call to get all books written or co-written by Leo Tolstoy:

This call is equivalent to this more complex one:

Similarly, you can use "HOLDS" within "join on=" to join two tables together based on values within list fields. For example, if information about authors is stored within its own database table, "Authors", and you wanted to display a table of books, their authors, and those authors' dates of birth, you could have the following call:

This is equivalent to the explicit call of:

"HOLDS LIKE"
There is an additional command, "HOLDS LIKE", that maps the SQL "LIKE" command onto all of a list of values; it works just like "HOLDS". For instance, to get all books written or co-written by anyone with "Leo" in their name, you could call:

The "NEAR" command
Like arrays, coordinates are not well-supported overall by relational databases. For that reason, similarly to arrays, coordinates have special handling for both storage and querying. For the case of coordinates, if you want to query on coordinates, the recommended approach is to use the "NEAR" command, which like "HOLDS" is a virtual command, defined by Cargo.

"NEAR" finds all the points near a specified set of coordinates, within a specified distance. The coordinates and distance must be placed in parentheses, separated by commas; and the distance must be in either kilometers (specified as "kilometers" or "km") or miles (specified as "miles" or "mi").

For instance, if there is a table called "Restaurants", holding a list of restaurants, and it contains a field called "Coords" holding the coordinates of each field, you could call the following query to display all restaurants (and some relevant information about them) within 10 kilometers of the Piazza San Marco in Italy:

Using SQL functions
You can include native functions from whichever database system you're using within #cargo_query, in the "fields", "join on" and "where" parameters. For MySQL, for example, you can see the set of defined string functions here, and the set of date functions here. Below are some examples of how SQL functions can be used, all assuming a MySQL system.


 * Custom link text: You can use CONCAT to create custom link text for both internal and external links.


 * Date filtering: You can use date functions like DATEDIFF to get items with a date within a certain range.


 * Truncating strings: You can use string functions like LEFT or SUBSTRING to trim strings. The following example also uses CONCAT and IF to append an ellipsis, only if the string value (a quote) has been truncated.

Configuration
There are several settings you can add to LocalSettings.php to change the display of query results:
 * <tt>$wgCargoDefaultQueryLimit</tt> - the number of results to show for #cargo_query if no limit is set (default is 100)
 * <tt>$wgCargoMaxQueryLimit</tt> - the maximum allowed number of results for #cargo_query (default is 5000)
 * <tt>$wgCargoDecimalMark</tt> - the character that separates between the main number and the decimal part for numbers on this wiki (depends on the wiki's country of origin) (default is ".")
 * <tt>$wgCargoDigitGroupingCharacter</tt> - the character that separates digits (usually thousands) for numbers on this wiki (default is ",")

If any of these are added to LocalSettings.php, they should be placed below the inclusion of Cargo.