Skip to content
This repository has been archived by the owner on Jun 4, 2022. It is now read-only.

Templating Data Model

Adrian Cochrane edited this page May 28, 2018 · 4 revisions

While Odysseus's "Prosody" templating language is heavily based on Django's, the simple fact we use different implementation languages changed the nature of our datamodels. Specifically whereas Django could lean on Python's datamodel and add minor polish, Prosody didn't have that convenience - which I think made it better.

In a sentance Prosody has a dynamic and coercive datamodel with silent errors. Here:

  • "Dynamic" means it exposes whatever property fields are given to it by query params, the database, or HTTP requests. This is contrast to the strongly-typed Vala language which requires these attributes to be accessed via methods.
  • "Coercive" means data is implicitly converted to text, iterable key-value mappings, numbers, or booleans according to the needs of the expression it's used in. But unlike JavaScript each type of expression only coerces to a fixed type, so Prosody has none of those pains.
  • "Silent errors" means that if you lookup a property that doesn't exist or do something else that doesn't make sense, rather than throw an error it will simply yield an "empty" value. This empty value then coerces to an empty string or 0.

These characteristics combine to make Prosody very resiliant to any input errors, according to Postel's Law.

Under the hood

This datamodel is implemented as a common interface over GLib.Value, Gee.Map, SQLite values and result arrays, JSON-GLib Nodes, and potentially LibXML Nodes with some minor enhancements to how these objects coerce between types. In addition to some implementations that can be manually assembled into template inputs.

Coercion rules

To start here's some general rules that are followed accross Prosody:

  • String coercions provide a human readable text of any value.
  • Any non-empty value coerces to true, and any empty value coerces to false. This very much follows Python rules.
  • Numbers coerce to a list of numbers from 0 up-to but not incuding that number.
  • Strings coerce to a list (with $i keys) of it's characters or it's parsed number.
  • When a collection is coerced to a number, it becomes the length of said collection.

And for specific sources of input:

  • Database results are generally treated as numbers, unless you ask for it's string.
  • Query parameters coerce to booleans representing their presence, strings representing their first occurance, or lists (with $i keys) of all their occurences in the query string. Coercion to numbers follows the rules for collections.
  • {% fetch %} naturally parses TSV data to a 2D list.