Metadata in Malloy
Malloy<br>Blog
All Posts
VSCode
Metadata in Malloy: Annotations and Tags
VSCode
Annotation and Tagging are a pair of features for attaching metadata to objects in a Malloy model.<br>The idea of attaching metadata to fragments of a program is a common one in modern programing languages.<br>When designing this feature for Malloy, we were not certain what uses there might be for metadata, because a Malloy model is<br>a slightly different kind of programming and might have slightly different requirments for its metadata.
Because of this, the main feature of the Malloy design for annotation is that it imposes almost no<br>structure on what kinds of data might be contained in the annotations. Annotations in Malloy are surface<br>which is flexible and powerful, to allow users of Malloy to investigate the possibilities of<br>annotation that we were unable to envision when we designed Malloy.
Malloy uses annotation sparingly, but we are noticing more projects using Malloy and taking advantage of annotations, and<br>now seemed like a good time to go into a little more detail on the feature so that it would be clear<br>how to take advantage of all the power offered by annotations.
Annotations
Annotations can be attached to models, sources, queries, views, and and field calculations. (e.g. dimensions, measures, caclucations, etc.)<br>An annotation is some text starting with the # character and continuing to the end of the line.
Annotation lines beginning with ## are applied to the model. Annotations beginning with a single # are applied to the next object being defined.
## (def model-level-notice "This is a model level annotation")
# "queryProperties": { "notice": "This annotation is attach to the query 'first_row'" }<br>query: first_row is some_src -> {select: *; limit 1}<br>You will notice in these examples that each annotation is written in a different language, this is<br>just an example of what is possible. An application can choose to parse its own annotations any<br>way it chooses, or even to not parse them at all and simply use them as free form text. There is a<br>Malloy companion property language (Malloy Tag Language) designed to be used with annotations, but<br>applications are free to interpret their annotations in any way which make sense to them.
Annotation Prefixes
Multiple applications can decorate a Malloy model with annotations, and there is a convention which will<br>allow applications to add annotations even without being aware of each other. This is the "annotation prefix".
When an application requests annotations for an object, a regular expression is passed along with the request,<br>and only annotations matching that regular expression are returned. Here are some example annotation usages with<br>their annotation prefixes:
prefix: /^# /
Instructions to the Malloy rendering library
Example: # chart { type=bar variant=stacked }
Parsed by the renderer using the Malloy Tag Language (See the Render Tag Documentaion)
prefix: /^##!/
Flags to control the Malloy to SQL translator
Example: ##! experimental { featureName1 }
Parsed by the Malloy translator, alsing using the Malloy Tag Language (See Experimental Features)
prefix : /^#"/
Doc strings for describing objects
Example: #" This source requires a date filter expression (fex)
Parsed by: Nothing yet, this is aspirational. Our intention is this would be where developer documentation<br>for reusable components in Malloy models would be written, allowing an IDE to use the annotations to offer information to developers.
prefix: /#(yourApp)/
Annotations for the app yourApp
Example: #(docs) size=medium
We use the (docs) prefix internally to attach formatting instructions for the Malloy documentation package.
Indirect Annotations
In addition to annotations directly placed on an object, there are two other ways for an object to have annotation metadata.
If one object is an extension, or refinement of an existing object, it will have all the annotations of the object it is based on, as well as it's own annotations. For example
// this will render as a bar chart<br># bar_chart<br>view: by_color is { group_by: color; aggregate: thing_count is count() }
// will "inherit" the bar_char annotation from by_color<br>view: by_color_and_size is by_color + { group_by: size }
// will show the by_color bar chart, only for the most common colors<br>nest: top_colors is by_color + { limit: 5 }<br>The other indirect way annotations can be placed on an object is available to objects which can be defined with a single statement
// Every measure defined in this measure statement will have the "private" annotation, in addition<br>// to any annotations on the actual object.<br># private<br>measure:<br># currency=US_DOLLARS<br>total_revenue is sum(revenue)<br># font_color=green<br>profitable is pick 'Yes' when sum(revenue) > sum(cost) else 'No'
The Malloy Tag Language
In some of the examples above we showed annotations intended be be parsed by an S-Expression parser and a JSON Parser,<br>but Malloy also has its own...