Skip to content

Commit

Permalink
add support for measures
Browse files Browse the repository at this point in the history
  • Loading branch information
owlas committed Apr 17, 2021
1 parent e0d87a3 commit e4b6d93
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 8 deletions.
32 changes: 26 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ Use `dbt2looker` to generate Looker view files automatically from dbt models.

**Features**

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

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

### Usage
## Quickstart

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

Expand Down Expand Up @@ -56,3 +57,22 @@ poetry install
# Run
poetry run dbt2looker
```

## Defining measures

You can define looker measures in your dbt `schema.yml` files. For example:

```yaml
models:
- name: pages
columns:
- name: url
description: "Page url"
- name: event_id
description: unique event id for page view
meta:
looker.com: # looker config block for column
measures:
- name: Page views
type: count
```
13 changes: 13 additions & 0 deletions dbt2looker/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,26 @@ def lookml_dimensions_from_model(model: models.DbtModel, adapter_type: models.Su
]


def lookml_measures_from_model(model: models.DbtModel):
return [
{
'name': measure.name,
'type': measure.type.value,
'sql': f'${{TABLE}}.{column.name}',
}
for column in model.columns.values()
for measure in column.meta.looker.measures
]


def lookml_view_from_dbt_model(model: models.DbtModel, adapter_type: models.SupportedDbtAdapters):
lookml = {
'view': {
'name': model.name,
'sql_table_name': f'{model.database}.{model.db_schema}.{model.name}',
'dimension_groups': lookml_dimension_groups_from_model(model, adapter_type),
'dimensions': lookml_dimensions_from_model(model, adapter_type),
'measures': lookml_measures_from_model(model),
}
}
contents = lkml.dump(lookml)
Expand Down
36 changes: 35 additions & 1 deletion dbt2looker/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from pydantic import BaseModel, Field, PydanticValueError, validator


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


class DbtProjectConfig(BaseModel):
# Lookml types
class LookerAggregateMeasures(str, Enum):
average = 'average'
average_distinct = 'average_distinct'
count = 'count'
count_distinct = 'count_distinct'
list = 'list'
max = 'max'
median = 'median'
median_distinct = 'median_distinct'
min = 'min'
percentile = 'percentile'
percentile_distinct = 'percentile_distinct'
sum = 'sum'
sum_distinct = 'sum_distinct'


class Dbt2LookerMeasure(BaseModel):
name: str
type: LookerAggregateMeasures


class Dbt2LookerMeta(BaseModel):
measures: Optional[List[Dbt2LookerMeasure]] = []


# Looker file types
class LookViewFile(BaseModel):
filename: str
contents: str
Expand All @@ -28,10 +52,20 @@ class LookModelFile(BaseModel):
contents: str


# dbt config types
class DbtProjectConfig(BaseModel):
name: str


class DbtModelColumnMeta(BaseModel):
looker: Optional[Dbt2LookerMeta] = Field(Dbt2LookerMeta(), alias='looker.com')


class DbtModelColumn(BaseModel):
name: str
description: str
data_type: Optional[str]
meta: DbtModelColumnMeta


class DbtNode(BaseModel):
Expand Down
5 changes: 5 additions & 0 deletions example/lookml/views/pages.view
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,9 @@ view: pages {
sql: ${TABLE}.referring_domain ;;
description: "Website domain of the referrer. e.g. google.com"
}

measure: Page views {
type: count
sql: ${TABLE}.id ;;
}
}
5 changes: 5 additions & 0 deletions example/models/prod/pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ models:
columns:
- name: id
description: "The primary key for this table"
meta:
looker.com:
measures:
- name: Page views
type: count
tests:
- unique
- not_null
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "dbt2looker"
version = "0.5.2"
version = "0.6.0"
description = "Generate lookml view files from dbt models"
authors = ["oliverlaslett <[email protected]>"]
license = "MIT"
Expand Down

0 comments on commit e4b6d93

Please sign in to comment.