Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,11 @@ dist
vite.config.js.timestamp-*
vite.config.ts.timestamp-*


.venv/
.user.yml
.env
profiles.yml
target/
dbt_packages/
logs/
71 changes: 57 additions & 14 deletions AI_ASSIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,74 @@ Document one place you used an LLM during this assignment.

## The problem

<!-- TODO: describe the specific problem you asked an LLM about.
Example: "My safe_divide macro compiled but returned NULL for all rows even
when tip_amount and fare_amount were both non-zero." -->

TODO
After adding the `dbt_utils.unique_combination_of_columns` test to `fct_daily_borough_stats`, I ran `dbt parse`. The project parsed, but dbt showed a deprecation warning about generic test arguments. I wanted to understand what the warning meant and how to update the YAML syntax correctly.

## The prompt

<!-- TODO: paste the exact prompt you sent to the LLM. -->

TODO
```text
(.venv) pavel@Pavels-MacBook-Air c55-data-week-10 % ./.venv/bin/dbt parse --profiles-dir .
/Users/pavel/Desktop/data _learn/c55-data-week-10/.venv/lib/python3.9/site-packages/urllib3/__init__.py:35: NotOpenSSLWarning: urllib3 v2 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with 'LibreSSL 2.8.3'. See: https://github.com/urllib3/urllib3/issues/3020
warnings.warn(
23:12:57 Running with dbt=1.10.22
23:12:58 Registered adapter: postgres=1.9.1
23:12:58 Unable to do partial parsing because a project dependency has been added
23:13:00 [WARNING][MissingArgumentsPropertyInGenericTestDeprecation]: Deprecated
functionality
Found top-level arguments to test dbt_utils.unique_combination_of_columns
Arguments to generic tests should be nested under the arguments property.
23:13:00 Performance info: /Users/pavel/Desktop/data _learn/c55-data-week-10/target/perf_info.json
23:13:00 [WARNING][DeprecationsSummary]: Deprecated functionality
Summary of encountered deprecations:
- MissingArgumentsPropertyInGenericTestDeprecation: 1 occurrence
To see all deprecation instances instead of just the first occurrence of each,
run command again with the --show-all-deprecations flag. You may also need to
run with --no-partial-parse` as some deprecations are only encountered during
parsing.
What should I change?
```

## The response

<!-- TODO: summarise or paste what the LLM returned. -->
The LLM explained that the test logic was correct, but the YAML used an older style for passing arguments to a generic test. It said that in newer dbt style, test parameters should be placed under an explicit `arguments:` key.

It suggested changing this:

```yaml
tests:
- dbt_utils.unique_combination_of_columns:
combination_of_columns:
- pickup_borough
- pickup_date
```

to this:

TODO
```yaml
tests:
- dbt_utils.unique_combination_of_columns:
arguments:
combination_of_columns:
- pickup_borough
- pickup_date
```

## Reflection

<!-- TODO: what did you change, keep, or discard after reviewing the LLM's answer?
Be specific: "I kept the NULLIF suggestion but changed the column alias from
'ratio' to 'tip_pct' to match the assignment schema." -->
I kept the `arguments:` suggestion because it removed the dbt deprecation warning while keeping the same test logic: one row per combination of `pickup_borough` and `pickup_date`.

I did not change the grain of the mart or the tested columns. I only changed the YAML syntax for the generic test arguments.

After the change, `dbt parse` ran without the deprecation warning, and the mart tests completed successfully:

```text
Done. PASS=4 WARN=0 ERROR=0 SKIP=0 NO-OP=0 TOTAL=4
```

Later, the full project build completed with one expected warning from the singular `avg_tip_pct` test:

TODO
```text
Done. PASS=11 WARN=1 ERROR=0 SKIP=0 NO-OP=0 TOTAL=12
```

---

Expand Down
Binary file added docs/lineage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 1 addition & 4 deletions macros/safe_divide.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,5 @@
-- Use for tip_pct = tip_amount / fare_amount and similar ratio columns.

{% macro safe_divide(numerator, denominator) %}
-- TODO: implement the macro body.
-- Use NULLIF(denominator, 0) to avoid division-by-zero errors.
-- Return only the SQL expression (no SELECT, no semicolon).
NULL
({{ numerator }} / nullif({{ denominator }}, 0))
{% endmacro %}
30 changes: 17 additions & 13 deletions models/marts/_fct_daily_borough_stats.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,27 @@ version: 2

models:
- name: fct_daily_borough_stats
description: >
TODO: state the grain (one row per ___), the source lineage
(built from ___ and ___), and at least one known caveat
(e.g. rows dropped in staging, any WARN-severity tests).
# TODO: Task 5 -- add the compound uniqueness test on the mart's primary
# key (pickup_borough, pickup_date). You need the dbt_utils package for
# this: declare it in packages.yml and run `dbt deps` first.
description: "Daily borough-level mart for NYC Green Taxi trips. The grain is one row per pickup borough and pickup date. The model is built from stg_trips joined to stg_zones using pickup_location_id. Trips with null pickup location ids or negative fares are removed in staging, and trips with pickup location ids that do not match a known TLC zone are dropped by the inner join. High average tip percentages are checked by a warning-level singular test because unusual tips can occur in low-volume borough/date combinations."
tests:
- dbt_utils.unique_combination_of_columns:
arguments:
combination_of_columns:
- pickup_borough
- pickup_date
columns:
- name: pickup_borough
description: "TODO: explain what this column contains and where it comes from"
description: "Borough label of the TLC pickup zone. This comes from stg_zones.borough and can include NYC boroughs as well as labels such as EWR, Unknown, or NaN."
tests:
- not_null
- name: pickup_date
description: "TODO: explain units and how it is derived"
description: "Calendar date of the trip pickup, derived from pickup_datetime. Unit: date."
tests:
- not_null
- name: trip_count
description: "TODO: explain what is counted (unit: number of trips)"
description: "Number of taxi trips picked up in the borough on the date. Unit: trips."
- name: total_fare
description: "TODO: explain units (USD) and what fare_amount represents"
description: "Sum of fare_amount for trips picked up in the borough on the date. Unit: US dollars."
- name: avg_tip_pct
description: "TODO: explain the ratio (tip_amount / fare_amount)"
description: "Average of tip_amount divided by fare_amount for trips picked up in the borough on the date. Unit: decimal ratio, where 0.2 means 20%."
- name: avg_trip_distance
description: "TODO: explain units (miles, from TLC source data)"
description: "Average trip_distance for trips picked up in the borough on the date. Unit: miles."
32 changes: 11 additions & 21 deletions models/marts/fct_daily_borough_stats.sql
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,15 @@ zones AS (
)

SELECT
-- TODO: join trips to zones on pickup_location_id = location_id.
-- Use an INNER JOIN: a few trips have a pickup_location_id with no matching
-- zone (e.g. 999). INNER JOIN drops those so pickup_borough is never NULL and
-- can serve as part of the mart's primary key (your not_null test needs this).
-- TODO: aggregate to grain (pickup_borough, pickup_date)
-- Required output columns:
-- pickup_borough TEXT - z.borough
-- pickup_date DATE - pickup_datetime::date
-- trip_count BIGINT - count(*)
-- total_fare NUMERIC - sum(fare_amount)
-- avg_tip_pct NUMERIC - avg(tip_pct)
-- avg_trip_distance NUMERIC - avg(trip_distance)
NULL AS pickup_borough,
NULL AS pickup_date,
NULL AS trip_count,
NULL AS total_fare,
NULL AS avg_tip_pct,
NULL AS avg_trip_distance

z.borough as pickup_borough,
t.pickup_datetime::date as pickup_date,
count(*) as trip_count,
sum(t.fare_amount) as total_fare,
avg(t.tip_pct) as avg_tip_pct,
avg(t.trip_distance) as avg_trip_distance
FROM trips t
-- TODO: add JOIN to zones here
-- TODO: add GROUP BY here
inner join zones z
on t.pickup_location_id = z.location_id
group by
z.borough,
t.pickup_datetime::date
6 changes: 3 additions & 3 deletions models/staging/_sources.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ version: 2

sources:
- name: nyc_taxi
schema: nyc_taxi # TODO: confirm this matches the schema where raw_trips and raw_zones live
schema: nyc_taxi
tables:
- name: raw_trips
description: "TODO: one sentence on what this table contains and its grain"
description: "Raw NYC Green Taxi trip records, with one row per taxi trip."
- name: raw_zones
description: "TODO: one sentence on what this table contains"
description: "Raw TLC taxi zone lookup table, with one row per location_id."
20 changes: 11 additions & 9 deletions models/staging/_stg_trips.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@ version: 2

models:
- name: stg_trips
description: "TODO: state the grain (one row per ___) and what source this reads from"
description: "Cleaned trip-level staging model for NYC Green Taxi trips, with one row per trip from raw_trips after removing rows with missing pickup location ids or negative fares."
columns:
- name: pickup_datetime
description: "TODO"
# TODO: Task 5 -- add not_null tests on every column used as a join or
# group-by key. See the chapter's dbt Tests section for the syntax.
description: "Timestamp when the trip started; used to derive pickup_date in the daily borough mart."
tests:
- not_null
- name: pickup_location_id
description: "TODO"
description: "TLC zone identifier where the trip started; used to join trips to stg_zones."
tests:
- not_null
- name: fare_amount
description: "TODO"
description: "Fare amount charged for the trip, in US dollars."
- name: tip_amount
description: "TODO"
description: "Tip amount paid for the trip, in US dollars."
- name: trip_distance
description: "TODO"
description: "Trip distance, in miles."
- name: tip_pct
description: "TODO"
description: "Tip amount divided by fare amount; null when fare amount is zero."
13 changes: 8 additions & 5 deletions models/staging/_stg_zones.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ version: 2

models:
- name: stg_zones
description: "TODO: state the grain and what source this reads from"
description: "Cleaned TLC taxi zone lookup staging model, with one row per location_id from raw_zones."
columns:
- name: location_id
description: "TODO"
# TODO: Task 5 -- this column is the join key. Which two generic tests
# guarantee a clean one-to-many join from stg_trips?
description: "Unique TLC zone identifier used to join trips to pickup boroughs."
tests:
- not_null
- unique
- name: borough
description: "TODO"
description: "Borough label for the TLC zone, including NYC boroughs plus values such as EWR, Unknown, and NaN."
tests:
- not_null
15 changes: 8 additions & 7 deletions models/staging/stg_trips.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
-- Downstream: fct_daily_borough_stats joins this to stg_zones.

SELECT
-- TODO: select the columns you need for the mart:
-- pickup_datetime, pickup_location_id, fare_amount, tip_amount, trip_distance
--
-- TODO: add tip_pct using {{ safe_divide('tip_amount', 'fare_amount') }}
--
-- TODO: filter out rows where pickup_location_id IS NULL or fare_amount < 0

pickup_datetime,
pickup_location_id,
fare_amount,
tip_amount,
trip_distance,
{{ safe_divide('tip_amount', 'fare_amount') }} as tip_pct
FROM {{ source('nyc_taxi', 'raw_trips') }}
where pickup_location_id is not null
and fare_amount >= 0
7 changes: 2 additions & 5 deletions models/staging/stg_zones.sql
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
-- Staging model: one row per TLC zone (265 zones).
-- Exposes location_id and borough for use as a lookup in the mart.

SELECT
-- TODO: select location_id and borough from {{ source('nyc_taxi', 'raw_zones') }}

location_id,
borough
FROM {{ source('nyc_taxi', 'raw_zones') }}
5 changes: 5 additions & 0 deletions package-lock.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
packages:
- name: dbt_utils
package: dbt-labs/dbt_utils
version: 1.3.0
sha1_hash: 226ae69cdfbc9367e2aa2c472b01f99dbce11de0
8 changes: 3 additions & 5 deletions packages.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# TODO: Task 5 -- declare the dbt-labs/dbt_utils package here, then run
# `dbt deps` to install it. You need it for the compound uniqueness test
# on the mart. See https://hub.getdbt.com/dbt-labs/dbt_utils/latest/
# for the package block syntax.
packages: []
packages:
- package: dbt-labs/dbt_utils
version: 1.3.0
Loading