Skip to content

Commit 9403a10

Browse files
committed
feat: add bronze-to-silver bigquery template
1 parent 8d1110c commit 9403a10

6 files changed

Lines changed: 306 additions & 0 deletions

File tree

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Bruin - Bronze to Silver BigQuery Template
2+
3+
This template delivers an end-to-end example of the bronze-to-silver pattern in
4+
Bruin. It ingests raw exchange rates from the credential-free Frankfurter API
5+
into BigQuery and then builds curated metrics that are ready for analytics.
6+
7+
The pipeline ships with:
8+
9+
- `bronze.frankfurter_rates`: An ingestr asset that captures daily FX rates in a
10+
bronze dataset.
11+
- `silver.fx_rate_enriched`: A BigQuery SQL asset that adds rolling averages,
12+
day-over-day deltas, and quality checks.
13+
- `.bruin.yml`: A starter configuration showing how to connect Frankfurter and
14+
Google Cloud.
15+
16+
## Setup
17+
18+
Initialize the template from the Bruin CLI:
19+
20+
```bash
21+
bruin init bronze-silver-bigquery
22+
```
23+
24+
Update the generated `.bruin.yml` with your Google Cloud project and service
25+
account. Frankfurter does not require credentials.
26+
27+
```yaml
28+
default_environment: default
29+
environments:
30+
default:
31+
connections:
32+
frankfurter:
33+
- name: "frankfurter-default"
34+
google_cloud_platform:
35+
- name: "gcp-default"
36+
project_id: "your-gcp-project-id"
37+
service_account_file: "/path/to/service-account.json"
38+
```
39+
40+
Create the `bronze` and `silver` datasets in BigQuery, or adjust the asset names
41+
to match datasets that already exist.
42+
43+
## Running the pipeline
44+
45+
From the template directory, validate the pipeline and then materialize it:
46+
47+
```bash
48+
bruin validate .
49+
bruin run .
50+
```
51+
52+
The run performs two steps:
53+
54+
1. Loads raw currency rates from Frankfurter into `bronze.frankfurter_rates`.
55+
2. Generates rolling metrics in `silver.fx_rate_enriched`, complete with sensible
56+
quality checks.
57+
58+
## Quality checks
59+
60+
- Bronze layer: not-null and positivity checks plus a custom validation that
61+
ensures the base currency remains EUR.
62+
- Silver layer: not-null and positivity checks on analytics columns and a custom
63+
query to guarantee rolling averages are present for historical data.
64+
65+
Use this template as the foundation for more advanced multi-layer pipelines or
66+
swap the source for any other ingestr-compatible system that does not require
67+
credentials.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
default_environment: default
2+
environments:
3+
default:
4+
connections:
5+
frankfurter:
6+
- name: "frankfurter-default"
7+
google_cloud_platform:
8+
- name: "gcp-default"
9+
project_id: "your-gcp-project-id"
10+
service_account_file: "/path/to/service-account.json"
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Bruin - Bronze to Silver BigQuery Template
2+
3+
This template demonstrates a complete bronze-to-silver pattern built on top of
4+
BigQuery. It combines a raw ingestion step powered by ingestr with a curated
5+
transformation layer that adds analytics-friendly aggregates and data quality
6+
checks.
7+
8+
## Pipeline Overview
9+
10+
- `assets/bronze_raw_data.asset.yml` creates the **bronze** layer by loading
11+
publicly available foreign exchange rates from the Frankfurter API into
12+
BigQuery.
13+
- `assets/silver_aggregated.sql` materializes the **silver** layer by computing
14+
rolling 7-day averages and day-over-day deltas for each currency.
15+
- `pipeline.yml` wires the assets together and defines default connections for
16+
Frankfurter and Google Cloud.
17+
- `.bruin.yml` contains a starter configuration you can adapt with your own
18+
GCP project and service account.
19+
20+
## Initialize the Template
21+
22+
```bash
23+
bruin init bronze-silver-bigquery
24+
```
25+
26+
This creates a folder with the files listed above so you can run the template in
27+
place or tailor it to your environment.
28+
29+
## Configure Connections
30+
31+
Update `.bruin.yml` with your Google Cloud project details and service account.
32+
The Frankfurter source does not require credentials, but you can rename the
33+
connection if desired.
34+
35+
```yaml
36+
default_environment: default
37+
environments:
38+
default:
39+
connections:
40+
frankfurter:
41+
- name: "frankfurter-default"
42+
google_cloud_platform:
43+
- name: "gcp-default"
44+
project_id: "your-gcp-project-id"
45+
service_account_file: "/path/to/service-account.json"
46+
```
47+
48+
> **BigQuery dataset**: The template writes to the `bronze` and `silver`
49+
> datasets. Create them ahead of time or change the dataset names in the asset
50+
> definitions to match your environment.
51+
52+
## Run the Pipeline
53+
54+
Validate and execute the pipeline from the template directory:
55+
56+
```bash
57+
bruin validate .
58+
bruin run .
59+
```
60+
61+
The bronze asset loads historical exchange rates, and the silver asset enriches
62+
that data with rolling metrics suitable for downstream analytics and reporting.
63+
64+
## Data Quality Highlights
65+
66+
- Every column in the bronze asset is monitored for nulls, and a custom check
67+
ensures the base currency remains `EUR`.
68+
- The silver layer adds positive and not-null checks, plus a custom validation
69+
that guarantees rolling averages are present for data older than seven days.
70+
71+
## Next Steps
72+
73+
- Swap in another no-auth source such as the Chess template by updating the
74+
`source_connection` and transformation logic.
75+
- Extend the silver layer with additional materializations (e.g. gold-level
76+
dashboards or alerts).
77+
- Schedule the pipeline using the `schedule` and `start_date` fields in
78+
`pipeline.yml` or integrate it with your orchestrator of choice.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: bronze.frankfurter_rates
2+
type: ingestr
3+
4+
description: |
5+
Ingests daily exchange rate data from the public Frankfurter API into BigQuery
6+
without requiring credentials. The bronze layer captures the raw payload so
7+
downstream transformations can compute rolling trends and quality metrics.
8+
9+
columns:
10+
- name: date
11+
type: timestamp
12+
description: "UTC timestamp returned by the Frankfurter exchange rate feed"
13+
checks:
14+
- name: not_null
15+
- name: currency_code
16+
type: string
17+
description: "ISO 4217 code for the quoted currency in the rates dataset"
18+
checks:
19+
- name: not_null
20+
- name: base_currency
21+
type: string
22+
description: "ISO 4217 code of the base currency (EUR by default in Frankfurter)"
23+
checks:
24+
- name: not_null
25+
- name: rate
26+
type: numeric
27+
description: "Exchange rate value for currency_code relative to base_currency"
28+
checks:
29+
- name: not_null
30+
- name: positive
31+
32+
custom_checks:
33+
- name: ensure_eur_reference
34+
description: "Verify that the base currency remains EUR for the raw snapshot"
35+
value: 0
36+
query: |
37+
SELECT COUNT(*) AS mismatch_count
38+
FROM bronze.frankfurter_rates
39+
WHERE base_currency != 'EUR'
40+
41+
parameters:
42+
source_connection: frankfurter-default
43+
source_table: exchange_rates
44+
destination: bigquery
45+
destination_table: bronze.frankfurter_rates
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/* @bruin
2+
3+
name: silver.fx_rate_enriched
4+
type: bq.sql
5+
6+
materialization:
7+
type: table
8+
9+
description: |
10+
Enriches the bronze Frankfurter exchange rates with rolling aggregates and
11+
day-over-day deltas to illustrate a typical silver layer transformation in
12+
BigQuery.
13+
14+
depends:
15+
- bronze.frankfurter_rates
16+
17+
columns:
18+
- name: date
19+
type: date
20+
description: "Date of the exchange rate observation"
21+
primary_key: true
22+
checks:
23+
- name: not_null
24+
- name: currency_code
25+
type: string
26+
description: "ISO 4217 code for the quoted currency"
27+
primary_key: true
28+
checks:
29+
- name: not_null
30+
- name: base_currency
31+
type: string
32+
description: "Reference currency that the rate is quoted against"
33+
checks:
34+
- name: not_null
35+
- name: rate
36+
type: numeric
37+
description: "Spot exchange rate value for the currency on the given date"
38+
checks:
39+
- name: not_null
40+
- name: positive
41+
- name: avg_rate_7d
42+
type: numeric
43+
description: "Seven day rolling average to smooth short term volatility"
44+
checks:
45+
- name: not_null
46+
- name: positive
47+
- name: change_vs_prev_day
48+
type: numeric
49+
description: "Day-over-day change in the exchange rate"
50+
checks:
51+
- name: not_null
52+
53+
custom_checks:
54+
- name: ensure_rolling_average_populated
55+
description: "Ensure rows older than a week carry a computed rolling average"
56+
value: 0
57+
query: |
58+
SELECT COUNT(*) AS missing_average
59+
FROM silver.fx_rate_enriched
60+
WHERE avg_rate_7d IS NULL
61+
AND date <= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
62+
63+
@bruin */
64+
65+
WITH cleaned_rates AS (
66+
SELECT
67+
DATE(date) AS rate_date,
68+
currency_code,
69+
base_currency,
70+
SAFE_CAST(rate AS NUMERIC) AS rate
71+
FROM `bronze.frankfurter_rates`
72+
WHERE DATE(date) >= DATE_SUB(CURRENT_DATE(), INTERVAL 90 DAY)
73+
),
74+
enriched AS (
75+
SELECT
76+
rate_date,
77+
currency_code,
78+
base_currency,
79+
rate,
80+
AVG(rate) OVER (
81+
PARTITION BY currency_code
82+
ORDER BY rate_date
83+
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
84+
) AS avg_rate_7d,
85+
COALESCE(
86+
rate - LAG(rate) OVER (PARTITION BY currency_code ORDER BY rate_date),
87+
0
88+
) AS change_vs_prev_day
89+
FROM cleaned_rates
90+
)
91+
SELECT
92+
rate_date AS date,
93+
currency_code,
94+
base_currency,
95+
rate,
96+
avg_rate_7d,
97+
change_vs_prev_day
98+
FROM enriched
99+
ORDER BY date, currency_code;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
name: bronze-silver-bigquery
2+
schedule: daily
3+
start_date: "2024-01-01"
4+
5+
default_connections:
6+
google_cloud_platform: gcp-default
7+
frankfurter: frankfurter-default

0 commit comments

Comments
 (0)