A style guide and linter for Looker's LookML data modeling language
View the Project on GitHub looker-open-source/look-at-me-sideways
LAMS comes pre-bundled with a number of rules that reflect our opinionated best practices. However, sometimes you may want to implement your own rules that may be highly specific to your project/model.
To handle this, LAMS offers the ability to extend it with custom rules written in a LISP-based expression, specified inline in your project manifest. (LAMS can also accept custom rules written in Javascript, hosted externally, although this approach is discouraged)
Expression-based rules can be declared within your manifest’s LookML, and consist of four parts. By way of example:
# in manifest.lkml
# LAMS
# rule: prod_connection {
# description: "Models must use prod connection"
# match: "$.model.*"
# expr_rule: ( === ::match:connection "prod" ) ;;
# }
You can also quickly experiment with custom rule definitions in the Rule Sandbox
Here is what each part of the rule definition means:
match
: The value matched by the match expression. (The expression is invoked once for each time the pattern is matched in your project)path
: An array containing the path to the matched LookML. For example, ['$','model','my_model']
project
: The entire LookML project, in case you need to further reference any data from it within each matchrule-functions-doc.js
, that you can call for a comprehensive list of available functions. But, see expression examples below for some common and useful ones!Disclaimer: Expression evaluation is powered by the Liyad library. It both intends to prevent escalation of privleges, and, unlike Javascript evaluation, theoretically can do so. (See my writeup on this). However, it is still a very new project, so evaluate it accordingly.
The match
property accepts a JSON Path expression. Further documentation about the JSON Path syntax can be found in the docs of the underlying library jsonpath-plus.
Additionally, to avoid potential code-execution issues, LAMS limits filtering expressions to a property existence check, or a single equality or inequality operation between a property and a string, boolean, or undefined literal.
Note that while you can use unrooted paths to match things a bit more concisely (i.e. without the leading $.), using a rooted path means less ambiguity in case a LookML parameter is also valid in another context.
JSONpath | Description |
---|---|
$.model.* |
All models |
$.file.*.view.* |
All views across all files (once per declaration) |
$.model.*.view.* |
All views included in models (once per inclusion) |
$.model.*.explore.* |
All explores across all models |
$.model.foo.explore.* |
All explores in the foo model |
$.model.*.view.*[dimension,measure].* |
All dimensions and all measures across all models |
$.model[?(@.persist_for)] |
All models that declare persist_for |
(=== ::match:value_format_name "usd")
(!== ::match:type undefined)
E.g., does the label start with “Is” or “Has”? (Note that $match
is a function, and match
is the matched value)
($boolean ($match
"^Is |^Has "
::match:label
))
($all
(=== ::match:hidden true)
(=== ::match:extension_required true)
)
($any
(=== ::match:hidden true)
(=== ::match:extension_required true)
...
)
($let myvar (+ ::match:foo "_bar") )
(=== myvar "foo_bar")
Disclaimer: The use of javascript rules are a security tradeoff. Fundamentally, evaluating Javascript code on your local machine and/or CI server gives that code a lot of access. And, this code can be altered by anyone with access to the server on which it is hosted, as well as any LookML developer with access to develop in the LookML project (even without deploy permissions). For this reason, expression based rules are preferred, and javascript-based rules may be deprecated in the future.
If you nevertheless want LAMS to execute Javascript-based custom rules:
custom_rules: ["<url>"]
(inside a #LAMS
comment block)--allow-custom-rules
startup flag