Skip to content

Commit e4b6d93

Browse files
committed
add support for measures
1 parent e0d87a3 commit e4b6d93

File tree

6 files changed

+85
-8
lines changed

6 files changed

+85
-8
lines changed

README.md

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@ Use `dbt2looker` to generate Looker view files automatically from dbt models.
44

55
**Features**
66

7-
* Auto-generates a Looker view per dbt model
8-
* Supports dbt model and column-level descriptions
9-
* Automatically maps raw column types to looker types
10-
* Creates dimension groups for datetime/timestamp/date types
11-
* Currently supports: BigQuery, Snowflake, Redshift (postgres to come)
7+
* **Column descriptions** synced to looker
8+
* **Dimension** for each column in dbt model
9+
* **Dimension groups** for datetime/timestamp/date columns
10+
* **Measures** defined through dbt column `metadata` [see below](#defining-measures)
11+
* Looker types
12+
* Warehouses: BigQuery, Snowflake, Redshift (postgres to come)
1213

1314
[![demo](https://raw.githubusercontent.com/hubble-data/dbt2looker/main/docs/demo.gif)](https://asciinema.org/a/407407)
1415

15-
### Usage
16+
## Quickstart
1617

1718
Run `dbt2looker` in the root of your dbt project *after compiling looker docs*.
1819

@@ -56,3 +57,22 @@ poetry install
5657
# Run
5758
poetry run dbt2looker
5859
```
60+
61+
## Defining measures
62+
63+
You can define looker measures in your dbt `schema.yml` files. For example:
64+
65+
```yaml
66+
models:
67+
- name: pages
68+
columns:
69+
- name: url
70+
description: "Page url"
71+
- name: event_id
72+
description: unique event id for page view
73+
meta:
74+
looker.com: # looker config block for column
75+
measures:
76+
- name: Page views
77+
type: count
78+
```

dbt2looker/generator.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,26 @@ def lookml_dimensions_from_model(model: models.DbtModel, adapter_type: models.Su
164164
]
165165

166166

167+
def lookml_measures_from_model(model: models.DbtModel):
168+
return [
169+
{
170+
'name': measure.name,
171+
'type': measure.type.value,
172+
'sql': f'${{TABLE}}.{column.name}',
173+
}
174+
for column in model.columns.values()
175+
for measure in column.meta.looker.measures
176+
]
177+
178+
167179
def lookml_view_from_dbt_model(model: models.DbtModel, adapter_type: models.SupportedDbtAdapters):
168180
lookml = {
169181
'view': {
170182
'name': model.name,
171183
'sql_table_name': f'{model.database}.{model.db_schema}.{model.name}',
172184
'dimension_groups': lookml_dimension_groups_from_model(model, adapter_type),
173185
'dimensions': lookml_dimensions_from_model(model, adapter_type),
186+
'measures': lookml_measures_from_model(model),
174187
}
175188
}
176189
contents = lkml.dump(lookml)

dbt2looker/models.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from pydantic import BaseModel, Field, PydanticValueError, validator
44

55

6+
# dbt2looker utility types
67
class UnsupportedDbtAdapterError(PydanticValueError):
78
code = 'unsupported_dbt_adapter'
89
msg_template = '{wrong_value} is not a supported dbt adapter'
@@ -14,10 +15,33 @@ class SupportedDbtAdapters(str, Enum):
1415
snowflake = 'snowflake'
1516

1617

17-
class DbtProjectConfig(BaseModel):
18+
# Lookml types
19+
class LookerAggregateMeasures(str, Enum):
20+
average = 'average'
21+
average_distinct = 'average_distinct'
22+
count = 'count'
23+
count_distinct = 'count_distinct'
24+
list = 'list'
25+
max = 'max'
26+
median = 'median'
27+
median_distinct = 'median_distinct'
28+
min = 'min'
29+
percentile = 'percentile'
30+
percentile_distinct = 'percentile_distinct'
31+
sum = 'sum'
32+
sum_distinct = 'sum_distinct'
33+
34+
35+
class Dbt2LookerMeasure(BaseModel):
1836
name: str
37+
type: LookerAggregateMeasures
38+
39+
40+
class Dbt2LookerMeta(BaseModel):
41+
measures: Optional[List[Dbt2LookerMeasure]] = []
1942

2043

44+
# Looker file types
2145
class LookViewFile(BaseModel):
2246
filename: str
2347
contents: str
@@ -28,10 +52,20 @@ class LookModelFile(BaseModel):
2852
contents: str
2953

3054

55+
# dbt config types
56+
class DbtProjectConfig(BaseModel):
57+
name: str
58+
59+
60+
class DbtModelColumnMeta(BaseModel):
61+
looker: Optional[Dbt2LookerMeta] = Field(Dbt2LookerMeta(), alias='looker.com')
62+
63+
3164
class DbtModelColumn(BaseModel):
3265
name: str
3366
description: str
3467
data_type: Optional[str]
68+
meta: DbtModelColumnMeta
3569

3670

3771
class DbtNode(BaseModel):

example/lookml/views/pages.view

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,9 @@ view: pages {
5050
sql: ${TABLE}.referring_domain ;;
5151
description: "Website domain of the referrer. e.g. google.com"
5252
}
53+
54+
measure: Page views {
55+
type: count
56+
sql: ${TABLE}.id ;;
57+
}
5358
}

example/models/prod/pages.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ models:
77
columns:
88
- name: id
99
description: "The primary key for this table"
10+
meta:
11+
looker.com:
12+
measures:
13+
- name: Page views
14+
type: count
1015
tests:
1116
- unique
1217
- not_null

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "dbt2looker"
3-
version = "0.5.2"
3+
version = "0.6.0"
44
description = "Generate lookml view files from dbt models"
55
authors = ["oliverlaslett <[email protected]>"]
66
license = "MIT"

0 commit comments

Comments
 (0)