Custom Style Rules
By default, the Style Validator will test for a variety of style violations using the base ruleset.
However, you can also add custom rules to your lkmlstyle.yaml
config file that either a) modify and override existing rules, or b) define completely new ones.
You can find the YAML definitions for all of the predefined rules in the base ruleset in this public GitHub repo.
If you create a rule that you think could be useful for the Looker community, please open a Pull Request so others can benefit from your rule!
We're always happy to help you develop a custom style rule for your team. If you need help, send us a message using the in-app chat, or an email at support@spectacles.dev!
Anatomy of a custom rule
Custom rule definitions go in your lkmlstyle.yaml
file, under the custom_rules
key.
Here's what a custom rule definition looks like:
custom_rules:
- title: Name of count measure doesn't start with 'c_'
code: M100
rationale: >
You should explicitly state the aggregation type in the dimension name
because it makes it easier for other developers and Explore users
to understand how the measure is calculated.
select:
- measure
filter:
- type: ParameterFilter
parameter_name: type
value: count
type: PatternMatchRule
regex: '^c_'
This rule checks all measures with type: count
and makes sure the name of each measure starts with c_
.
Let's unpack this definition parameter-by-parameter and explain what each means. We'll start with the parameters that apply to all rule types.
Global rule parameters
title
title: Name of count measure doesn't start with 'c_'
This is the "name" of the rule and will be shown to developers when the Style Validator raises violations.
By convention, the title should be in the form of a complaint, saying what the problem is. Prefer, "Dimension does not define a description" instead of, "All dimensions should define descriptions" or, "Dimensions without descriptions".
code
code: M100
The desired rule code. If you specify a rule code that already exists in the base ruleset, the Style Validator will override the base rule with your custom rule.
Each code should start with a capital letter and end with a 3-digit number, e.g. V100
. Use a letter that corresponds to the LookML entity for the rule. For example, V401
for a view or J201
for a join.
rationale
rationale: >
You should explicitly state the aggregation type in the dimension name
because it makes it easier for other developers and Explore users
to understand how the measure is calculated.
A descriptive explanation for why the rule should be enforced. This helps developers who encounter style violations understand why they should fix the violation.
In YAML, you can use the >
block style indicator to indicate that newlines in the string should be replaced with spaces.
This is helpful if you want to write out a long block of text over multiple lines in a YAML file.
select
select:
- measure
The type of LookML entity to test. This can be a basic type like explore
or dimension
, or a dot-delimited string indicating ancestry.
For example, the following would to test the sql_table_name
field for dimensions but not views.
select:
- dimension.sql_table_name
You can select multiple entities. For example, to select dimension
and dimension_group
, you would specify the following:
select:
- dimension
- dimension_group
Or, in array syntax for conciseness:
select: [dimension, dimension_group]
filter
filter:
- type: ParameterFilter
parameter_name: type
value: count
Filters help us narrow down the LookML entities to be tested.
Without a filter, the Style Validator would test all measures as defined by select
above. Instead, we're testing only measures with type: count
. Here's an example of a measure that would be tested under this filter:
measure: orders {
type: count
sql: ${order_id} ;;
}
By default, the Style Validator will test any LookML entity whose type matches the lineage defined in select
(see above).
In many cases, testing all selected entities (i.e. all measures, explores, etc.) will not be specific enough. For example, you might want to test only the dimensions that are primary keys, or only the measures that define filters.
In these instances, you can define one or more filters to narrow down the entities to test.
Spectacles may eventually support different types of filters, but for now, you can only define a ParameterFilter
, which checks for the presence of a parameter on the selected entity, optionally filtering for its value.
You can omit value
to filter only for entities that define the parameter, regardless of its value.
filter:
- type: ParameterFilter
parameter_name: derived_table
Composing multiple filters
You can string together multiple filters using the boolean operators AND
, OR
, and NOT
. Here's a filter that tests views that are not extensions but do have a sql_table_name
or derived_table
parameter.
filter:
- type: ParameterFilter
parameter_name: derived_table
- operator: OR
type: ParameterFilter
parameter_name: sql_table_name
- operator: NOT
type: ParameterFilter
parameter_name: extends
We could represent this filter as derived_table OR sql_table_name AND NOT extends
.
It's also possible to nest these definitions as if you were wrapping boolean expressions in parenthesis. Imagine a filter that tests for the presence of A or B and not C. We could represent this expression as (A OR B) AND NOT C
.
filter:
- nest:
- type: ParameterFilter
parameter_name: A
- operator: OR
type: ParameterFilter
parameter_name: B
- operator: NOT
type: ParameterFilter
parameter_name: C
The array key nest
is used to represent the parentheses surrounding A OR B
in the Boolean expression.
type
type: PatternMatchRule
The type of style rule. This rule is a PatternMatchRule
, which applies a regex to the name of the selected LookML entity.
The Style Validator can enforce three types of generic rules:
PatternMatchRule
ParameterRule
OrderRule
Let's start with the PatternMatchRule
and learn how we can configure it.
PatternMatchRule
A PatternMatchRule
checks to see if a LookML entity's value matches a specified regular expression.
For blocks like view
, measure
, join
, etc., value refers to the name of the entity. For example, for the following LookML:
view: orders {
...
}
the value of the LookML entity is the name, "orders".
For key/value pairs like hidden: yes
or type: count
, the value of the entity is the value in the key/value pair. For the above examples, the values are "yes" and "count".
This means the value tested will ultimately depend on what you are selecting in your select
parameter. Selecting dimension
means you'll be testing the name of every dimension. Selecting dimension.label
means you'll be testing the value of the label on every dimension.
regex
regex: '^c_'
The regular expression to test with. If no match is found, the Style Validator raises a violation. In this case, we're using the pattern ^c_
to ensure the name of the measure starts with c_
.
Putting regular expressions inside YAML files can occasionally lead to unexpected results when parts of the regular expression are parsed as YAML syntax.
To avoid this, we recommend single-quoting regular expression strings in your configuration file. This will allow you to escape special characters in a regular expression as you would normally.
Read more about regex in YAML on Christophe Henry's blog.
Altogether, you should now be able to see that this rule selects any measure with type: count
and checks that its name matches the regular expression ^c_
. If a measure doesn't match, this rule results in a violation with the code M100.
ParameterRule
A ParameterRule
checks to see if a LookML entity contains a given parameter.
For example, check that every dimension defines the parameter description
, or check that all dimensions that define the parameter primary_key
also define the parameter hidden: yes
.
Here's an example of a parameter rule from the base ruleset.
- title: Visible measure missing description
code: M112
rationale: >
Measures that are visible in the Explore page should have a description
so users understand how and why to use them, along with any caveats.
select:
- measure
filter:
- operator: NOT
type: ParameterFilter
parameter_name: hidden
value: 'yes'
type: ParameterRule
criteria:
- type: ParameterFilter
parameter_name: description
criteria
criteria:
- type: ParameterFilter
parameter_name: description
A ParameterRule
must define criteria
, which is a ParameterFilter
representing the test to apply. In the example above, the rule checks measures (filtered for NOT hidden: yes
) to see if they have defined the description
parameter.
criteria_on
A ParameterRule
can also define criteria_on
, which is a select
string applied to the direct descendants of the selected LookML entity. For example, we may want to flag all views that don't define a primary key dimension. In that case, we want to select the view, but we want to test its child dimensions. Providing criteria_on: dimension
allows us to do this.
OrderRule
An OrderRule
checks that the selected LookML entity is in the proper order within a file. For example, we could use an OrderRule
to enforce alphabetical order of dimensions, or enforce primary keys as the first dimension within a view.
By default, OrderRule
checks order based on the value of the node. See regex
above to understand how the value is determined for a LookML entity.
Here's an example of an OrderRule
:
- title: Primary key dimension not the first dimension in this view
code: D107
rationale: >
The primary key should be listed first in a view so developers quickly understand the grain of the view and what a single record represents.
select:
- dimension
filter:
- type: ParameterFilter
parameter_name: primary_key
value: 'yes'
type: OrderRule
is_first: true
This rule checks that, within a single file, the dimension with primary_key: yes
is the first dimension in the file.
In YAML, unquoted yes
or no
strings are parsed as boolean True/False values. If you're creating a rule for a yes/no parameter and need to provide yes
or no
as a value, make sure you wrap it in quotes.
filter:
- type: ParameterFilter
parameter_name: primary_key
value: 'yes'
alphabetical
, is_first
, and order
is_first: true
The OrderRule
supports three orderings. Remember, these orderings use the value of each node when comparing.
- Alphabetical (
alphabetical
) - each selected node must be alphabetically ordered when compared to the other selected nodes. - First of N (
is_first
) - the filtered node must appear first when compared to the other selected nodes. - Custom Order (
order
) - the selected nodes must follow a custom order of user-supplied values.
The desired ordering approach should be specified as a mutually exclusive boolean flag, e.g. alphabetical: true
.
filter
When specified in an OrderRule
, filter
behaves differently depending on the ordering approach chosen. For is_first
, the filter is used to select the node that should be first, and select
is used to determine the set of nodes to consider.
For other approaches, the filter is used in addition to select
to determine the nodes to consider.