-
Notifications
You must be signed in to change notification settings - Fork 1
Build end-to-end dbt warehouse with cleaned staging, marts, tests, an… #76
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -9,27 +9,39 @@ version: '1.0.0' | |||||||||||||||||||||||||||||||||||
| profile: 'dbt_project' | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| # These configurations specify where dbt should look for different types of files. | ||||||||||||||||||||||||||||||||||||
| # The `model-paths` config, for example, states that models in this project can be | ||||||||||||||||||||||||||||||||||||
| # found in the "models/" directory. You probably won't need to change these! | ||||||||||||||||||||||||||||||||||||
| model-paths: ["models"] | ||||||||||||||||||||||||||||||||||||
| analysis-paths: ["analyses"] | ||||||||||||||||||||||||||||||||||||
| test-paths: ["tests"] | ||||||||||||||||||||||||||||||||||||
| seed-paths: ["seeds"] | ||||||||||||||||||||||||||||||||||||
| macro-paths: ["macros"] | ||||||||||||||||||||||||||||||||||||
| snapshot-paths: ["snapshots"] | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| clean-targets: # directories to be removed by `dbt clean` | ||||||||||||||||||||||||||||||||||||
| clean-targets: | ||||||||||||||||||||||||||||||||||||
| - "target" | ||||||||||||||||||||||||||||||||||||
| - "dbt_packages" | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| # Configuring models | ||||||||||||||||||||||||||||||||||||
| # Full documentation: https://docs.getdbt.com/docs/configuring-models | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| # In this example config, we tell dbt to build all models in the example/ | ||||||||||||||||||||||||||||||||||||
| # directory as views. These settings can be overridden in the individual model | ||||||||||||||||||||||||||||||||||||
| # files using the `{{ config(...) }}` macro. | ||||||||||||||||||||||||||||||||||||
| # Configuring models with Medallion Architecture layers | ||||||||||||||||||||||||||||||||||||
| models: | ||||||||||||||||||||||||||||||||||||
| dbt_project: | ||||||||||||||||||||||||||||||||||||
| silver: | ||||||||||||||||||||||||||||||||||||
| +materialized: table | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| # ─── Staging Layer (Bronze → Silver Raw Cleaning) ─── | ||||||||||||||||||||||||||||||||||||
| staging: | ||||||||||||||||||||||||||||||||||||
| +materialized: view | ||||||||||||||||||||||||||||||||||||
| +schema: silver | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| # ─── Intermediate Layer (Business Transformations) ─── | ||||||||||||||||||||||||||||||||||||
| intermediate: | ||||||||||||||||||||||||||||||||||||
| +materialized: view | ||||||||||||||||||||||||||||||||||||
| +schema: silver | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| # ─── Marts Layer (Gold Layer - Business Ready) ─── | ||||||||||||||||||||||||||||||||||||
| marts: | ||||||||||||||||||||||||||||||||||||
| dimensions: | ||||||||||||||||||||||||||||||||||||
| +materialized: table | ||||||||||||||||||||||||||||||||||||
| +schema: gold | ||||||||||||||||||||||||||||||||||||
| facts: | ||||||||||||||||||||||||||||||||||||
| +materialized: table | ||||||||||||||||||||||||||||||||||||
| +schema: gold | ||||||||||||||||||||||||||||||||||||
| reporting: | ||||||||||||||||||||||||||||||||||||
| +materialized: view | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+39
to
+46
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== marts directory names =="
fd -t d . script/silver/dbt_project/models/marts
echo
echo "== marts config keys in dbt_project.yml =="
rg -n '^\s{6}(dimensions|facts|reporting|Dimensions|Facts|Reporting):' script/silver/dbt_project/dbt_project.ymlRepository: Ritik574-coder/dbt_learning_project Length of output: 355 🌐 Web query:
💡 Result: In dbt, the Citations:
Fix casing mismatch for marts model config keys (dbt is case-sensitive) In Suggested fix marts:
- dimensions:
+ Dimensions:
+materialized: table
+schema: gold
- facts:
+ Facts:
+materialized: table
+schema: gold
- reporting:
+ Reporting:
+materialized: view
+schema: gold📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||
| +schema: gold | ||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| -- Intermediate Model: int_customers_standardized | ||
| -- Purpose: Further refine customer data with business-specific transformations | ||
|
|
||
| WITH staging AS ( | ||
| SELECT * FROM {{ ref('src_customers') }} | ||
| ) | ||
|
|
||
| SELECT | ||
| customer_id, | ||
| title, | ||
| first_name, | ||
| last_name, | ||
| CONCAT(first_name, ' ', last_name) AS full_name, | ||
| gender, | ||
| date_of_birth, | ||
| age, | ||
|
|
||
| CASE | ||
| WHEN age BETWEEN 0 AND 17 THEN 'Under 18' | ||
| WHEN age BETWEEN 18 AND 24 THEN '18-24' | ||
| WHEN age BETWEEN 25 AND 34 THEN '25-34' | ||
| WHEN age BETWEEN 35 AND 44 THEN '35-44' | ||
| WHEN age BETWEEN 45 AND 54 THEN '45-54' | ||
| WHEN age BETWEEN 55 AND 64 THEN '55-64' | ||
| WHEN age >= 65 THEN '65+' | ||
| ELSE 'Unknown' | ||
| END AS age_group, | ||
|
|
||
| email, | ||
| phone, | ||
| address, | ||
| city, | ||
| state_abbr, | ||
| state_full, | ||
| zip_code, | ||
| country, | ||
| region, | ||
| customer_segment, | ||
| loyalty_points, | ||
| is_active, | ||
| account_created_date, | ||
| preferred_channel, | ||
| annual_income_usd, | ||
| company, | ||
| GETDATE() AS _loaded_at | ||
| FROM staging |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,28 @@ | ||||||||||||||
| -- Intermediate Model: int_employees_standardized | ||||||||||||||
|
|
||||||||||||||
| WITH staging AS ( | ||||||||||||||
| SELECT * FROM {{ ref('src_employees') }} | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| SELECT | ||||||||||||||
| employee_id, | ||||||||||||||
| first_name, | ||||||||||||||
| last_name, | ||||||||||||||
| CONCAT(first_name, ' ', last_name) AS full_name, | ||||||||||||||
| email, | ||||||||||||||
| phone, | ||||||||||||||
| job_title, | ||||||||||||||
| department, | ||||||||||||||
| store_id, | ||||||||||||||
| store_name, | ||||||||||||||
| store_city, | ||||||||||||||
| hire_date, | ||||||||||||||
| years_employed, | ||||||||||||||
| annual_salary_usd, | ||||||||||||||
| commission_rate_pct, | ||||||||||||||
| is_active, | ||||||||||||||
| performance_rating, | ||||||||||||||
| manager_id, | ||||||||||||||
| DATEDIFF(YEAR, hire_date, GETDATE()) AS calculated_tenure_years, | ||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
FILE="script/silver/dbt_project/models/intermediate/Employees/int_employees_standardized.sql"
echo "== File header =="
sed -n '1,120p' "$FILE" | nl -ba | sed -n '1,120p'
echo
echo "== Context around calculated_tenure_years (lines 1..80 from around line 26) =="
# Print a safe window around line 26 (line numbers shown via nl)
START=10
END=60
nl -ba "$FILE" | sed -n "${START},${END}p"
echo
echo "== Search for hire_date usage/casting in this model =="
rg -n "hire_date|DATEDIFF\\(YEAR|calculated_tenure_years|tenure" "$FILE" || true
echo
echo "== Search repo for other tenure-year calculations patterns =="
rg -n "DATEDIFF\\(YEAR,\\s*hire_date|calculated_tenure_years|tenure_years" script/silver/dbt_project/models || trueRepository: Ritik574-coder/dbt_learning_project Length of output: 158 🏁 Script executed: #!/bin/bash
set -euo pipefail
FILE="script/silver/dbt_project/models/intermediate/Employees/int_employees_standardized.sql"
echo "== Exists? =="
ls -la "$FILE"
echo
echo "== File contents around start (first 120 lines) with line numbers =="
awk '{printf "%5d\t%s\n", NR, $0}' "$FILE" | sed -n '1,120p'
echo
echo "== Context around calculated_tenure_years (around line 26) =="
awk '{printf "%5d\t%s\n", NR, $0}' "$FILE" | sed -n '10,60p'
echo
echo "== Search within file for hire_date / calculated_tenure_years / tenure =="
rg -n "hire_date|DATEDIFF\(YEAR|calculated_tenure_years|tenure" "$FILE" || true
echo
echo "== Search repo for other tenure-year calculations patterns =="
rg -n "DATEDIFF\(YEAR,\s*hire_date|calculated_tenure_years|tenure_years" script/silver/dbt_project/models || trueRepository: Ritik574-coder/dbt_learning_project Length of output: 2360 🏁 Script executed: #!/bin/bash
set -euo pipefail
FILES=(
"script/silver/dbt_project/models/marts/Reporting/employee_performance.sql"
"script/silver/dbt_project/models/marts/Dimensions/dim_employees.sql"
)
for f in "${FILES[@]}"; do
echo "==================== $f ===================="
ls -la "$f"
echo "-- contents (with line numbers) --"
awk '{printf "%5d\t%s\n", NR, $0}' "$f" | sed -n '1,120p'
echo
done
echo "== Search for calculated_tenure_years definitions/overrides =="
rg -n "calculated_tenure_years\s*=|AS\s+calculated_tenure_years|DATEDIFF\\(YEAR,\\s*hire_date|tenure_years" script/silver/dbt_project/models || trueRepository: Ritik574-coder/dbt_learning_project Length of output: 2984 🏁 Script executed: #!/bin/bash
set -euo pipefail
rg -n "years_employed|calculated_tenure_years" script/silver/dbt_project/models || true
echo "== Search for hire_date type/casts in src_employees model =="
# Try common model names; list files that might define src_employees
fd "src_employees" script/silver/dbt_project/models || true
fd "src_employees*" script/silver/dbt_project/models || true
# Search for the src_employees definition if present
rg -n "ref\\('src_employees'\\)" script/silver/dbt_project/models || trueRepository: Ritik574-coder/dbt_learning_project Length of output: 1987 🏁 Script executed: #!/bin/bash
set -euo pipefail
FILE="script/silver/dbt_project/models/staging/src_employees.sql"
echo "== Exists? =="
ls -la "$FILE"
echo
echo "== Find hire_date handling in src_employees.sql =="
rg -n "hire_date" "$FILE" || true
echo
echo "== Show section around hire_date casts/logic (lines 1..220, then narrowed to matches) =="
awk '{printf "%5d\t%s\n", NR, $0}' "$FILE" | sed -n '1,220p' | tail -n +1
echo
echo "== Show near hire_date occurrences =="
# Extract line ranges around each match (simple approach: print fixed window around first few matches)
MATCH_LINES=$(rg -n "hire_date" "$FILE" | cut -d: -f1 | head -n 10 | tr '\n' ' ')
echo "Match lines: $MATCH_LINES"
for l in $MATCH_LINES; do
START=$((l-15)); END=$((l+25));
awk '{printf "%5d\t%s\n", NR, $0}' "$FILE" | sed -n "${START},${END}p"
echo "---"
doneRepository: Ritik574-coder/dbt_learning_project Length of output: 31416 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== Find all usages of years_employed and calculated_tenure_years across models =="
rg -n "years_employed|calculated_tenure_years" script/silver/dbt_project/models || true
echo
echo "== Check for any tenure calculation helpers (e.g., DATEADD/DATEDIFF YEAR adjustments) =="
rg -n "DATEDIFF\\(YEAR,\\s*|DATEADD\\(YEAR,\\s*DATEDIFF\\(YEAR" script/silver/dbt_project/models || trueRepository: Ritik574-coder/dbt_learning_project Length of output: 2152 Fix
💡 Proposed fix- DATEDIFF(YEAR, hire_date, GETDATE()) AS calculated_tenure_years,
+ DATEDIFF(YEAR, hire_date, CAST(GETDATE() AS DATE))
+ - CASE
+ WHEN DATEADD(YEAR, DATEDIFF(YEAR, hire_date, CAST(GETDATE() AS DATE)), hire_date) > CAST(GETDATE() AS DATE)
+ THEN 1 ELSE 0
+ END AS calculated_tenure_years,📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
| GETDATE() AS _loaded_at | ||||||||||||||
| FROM staging | ||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,24 @@ | ||||||||||||||
| -- Intermediate Model: int_inventory_summary | ||||||||||||||
|
|
||||||||||||||
| WITH staging AS ( | ||||||||||||||
| SELECT * FROM {{ ref('src_inventory') }} | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| SELECT | ||||||||||||||
| snapshot_date, | ||||||||||||||
| product_id, | ||||||||||||||
| product_name, | ||||||||||||||
| sku, | ||||||||||||||
| category, | ||||||||||||||
| stock_on_hand, | ||||||||||||||
| stock_reserved, | ||||||||||||||
| stock_available, | ||||||||||||||
| reorder_level, | ||||||||||||||
| unit_cost, | ||||||||||||||
| unit_price, | ||||||||||||||
| inventory_value, | ||||||||||||||
| CASE WHEN stock_available <= reorder_level THEN 'Yes' ELSE 'No' END AS needs_reorder, | ||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# 1) Show the exact line context around the reported CASE expression
file="script/silver/dbt_project/models/intermediate/Inventory/int_inventory_summary.sql"
if [ -f "$file" ]; then
echo "=== Context for $file (lines 1-80) ==="
sed -n '1,120p' "$file" | nl -ba | sed -n '1,120p'
else
echo "File not found: $file" >&2
exit 1
fi
# 2) Find other occurrences of needs_reorder / reorder_level / stock_available logic
echo "=== rg: needs_reorder ==="
rg -n "needs_reorder" script/silver/dbt_project/models || true
echo "=== rg: stock_available"===
rg -n "stock_available" script/silver/dbt_project/models/intermediate/Inventory || true
echo "=== rg: reorder_level"===
rg -n "reorder_level" script/silver/dbt_project/models/intermediate/Inventory || trueRepository: Ritik574-coder/dbt_learning_project Length of output: 255 🏁 Script executed: #!/bin/bash
set -euo pipefail
file="script/silver/dbt_project/models/intermediate/Inventory/int_inventory_summary.sql"
if [ -f "$file" ]; then
echo "=== Context for $file (lines 1-80) ==="
sed -n '1,120p' "$file" | awk '{printf "%d\t%s\n", NR, $0}'
else
echo "File not found: $file" >&2
exit 1
fi
echo "=== rg: needs_reorder ==="
rg -n "needs_reorder" script/silver/dbt_project/models || true
echo "=== rg: stock_available ==="
rg -n "stock_available" script/silver/dbt_project/models || true
echo "=== rg: reorder_level ==="
rg -n "reorder_level" script/silver/dbt_project/models || trueRepository: Ritik574-coder/dbt_learning_project Length of output: 4583 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Show relevant parts of the intermediate model
file="script/silver/dbt_project/models/intermediate/Inventory/int_inventory_summary.sql"
echo "=== int_inventory_summary.sql (full) ==="
sed -n '1,200p' "$file" | awk '{printf "%d\t%s\n", NR, $0}'
# Show how stock_available + reorder_level are produced in staging
file2="script/silver/dbt_project/models/staging/src_inventory.sql"
echo "=== src_inventory.sql (stock_available + reorder_level area) ==="
# Print around the relevant region
sed -n '50,120p' "$file2" | awk '{printf "%d\t%s\n", NR, $0}'
# Show downstream usage of needs_reorder
file3="script/silver/dbt_project/models/marts/Reporting/inventory_summary.sql"
echo "=== inventory_summary.sql (uses needs_reorder) ==="
sed -n '1,120p' "$file3" | awk '{printf "%d\t%s\n", NR, $0}'
file4="script/silver/dbt_project/models/marts/Facts/fct_inventory.sql"
echo "=== fct_inventory.sql (selects needs_reorder) ==="
sed -n '1,120p' "$file4" | awk '{printf "%d\t%s\n", NR, $0}'
# Look for schema/tests/docs mentioning needs_reorder
echo "=== rg: needs_reorder in schema.yml ==="
rg -n "needs_reorder" script/silver/dbt_project/models/marts/schema.yml || trueRepository: Ritik574-coder/dbt_learning_project Length of output: 5558 Preserve unknown reorder status when
💡 Proposed fix- CASE WHEN stock_available <= reorder_level THEN 'Yes' ELSE 'No' END AS needs_reorder,
+ CASE
+ WHEN stock_available IS NULL OR reorder_level IS NULL THEN NULL
+ WHEN stock_available <= reorder_level THEN 'Yes'
+ ELSE 'No'
+ END AS needs_reorder,📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
| warehouse_location, | ||||||||||||||
| store_id, | ||||||||||||||
| GETDATE() AS _loaded_at | ||||||||||||||
| FROM staging | ||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,39 @@ | ||||||||||||||
| -- Intermediate Model: int_products_standardized | ||||||||||||||
|
|
||||||||||||||
| WITH staging AS ( | ||||||||||||||
| SELECT * FROM {{ ref('src_products') }} | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| SELECT | ||||||||||||||
| product_id, | ||||||||||||||
| sku, | ||||||||||||||
| product_name, | ||||||||||||||
| brand, | ||||||||||||||
| category, | ||||||||||||||
| sub_category, | ||||||||||||||
| department, | ||||||||||||||
| base_price_usd, | ||||||||||||||
| cost_price_usd, | ||||||||||||||
| gross_margin_pct, | ||||||||||||||
| CASE WHEN base_price_usd > 0 THEN (base_price_usd - cost_price_usd) / base_price_usd * 100 ELSE NULL END AS calculated_margin_pct, | ||||||||||||||
| weight_kg, | ||||||||||||||
| is_available, | ||||||||||||||
| stock_quantity, | ||||||||||||||
| reorder_level, | ||||||||||||||
| CASE WHEN stock_quantity <= reorder_level THEN 'Yes' ELSE 'No' END AS low_stock_flag, | ||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# 1) Show the exact section around the referenced line in the file
FILE="script/silver/dbt_project/models/intermediate/Products/int_products_standardized.sql"
echo "=== File: $FILE (lines around 23) ==="
if [ -f "$FILE" ]; then
nl -ba "$FILE" | sed -n '1,120p' | sed -n '15,45p'
else
echo "Missing file: $FILE"
fi
# 2) Find all occurrences of low_stock_flag and the specific CASE predicate
echo
echo "=== Search: low_stock_flag occurrences ==="
rg -n "low_stock_flag" script/silver/dbt_project/models || true
echo
echo "=== Search: stock_quantity <= reorder_level occurrences ==="
rg -n "stock_quantity\s*<=\s*reorder_level" script/silver/dbt_project/models || true
# 3) Search for a likely inventory model that may use similar logic
echo
echo "=== Search: reorder_level usage (context) ==="
rg -n "reorder_level" script/silver/dbt_project/models/intermediate script/silver/dbt_project/models/silver script/silver/dbt_project/models || true
# 4) Inspect any candidate inventory/stock-risk logic files around similar flags
echo
echo "=== Search: low stock / low_stock / stock risk related ==="
rg -n "(low_stock|low stock|stock[_ ]risk|reorder_level)" script/silver/dbt_project/models || trueRepository: Ritik574-coder/dbt_learning_project Length of output: 257 🏁 Script executed: #!/bin/bash
set -euo pipefail
FILE="script/silver/dbt_project/models/intermediate/Products/int_products_standardized.sql"
echo "=== Check file exists: $FILE ==="
ls -l "$FILE" || true
echo
echo "=== File: $FILE (lines 15-45 with line numbers) ==="
if [ -f "$FILE" ]; then
awk 'NR>=15 && NR<=45 {printf "%d:%s\n", NR, $0}' "$FILE"
fi
echo
echo "=== Search: low_stock_flag occurrences ==="
rg -n "low_stock_flag" script/silver/dbt_project/models || true
echo
echo "=== Search: stock_quantity <= reorder_level occurrences ==="
rg -n "stock_quantity\s*<=\s*reorder_level" script/silver/dbt_project/models || true
echo
echo "=== Search: reorder_level usage (intermediate scope) ==="
rg -n "reorder_level" script/silver/dbt_project/models/intermediate || true
echo
echo "=== Search: stock risk / low stock related ==="
rg -n "(low_stock|low stock|stock[_ ]risk|reorder_level)" script/silver/dbt_project/models/intermediate || trueRepository: Ritik574-coder/dbt_learning_project Length of output: 3089 🏁 Script executed: #!/bin/bash
set -euo pipefail
FILE="script/silver/dbt_project/models/intermediate/Inventory/int_inventory_summary.sql"
echo "=== File: $FILE (lines 1-80) ==="
if [ -f "$FILE" ]; then
awk 'NR>=1 && NR<=80 {printf "%d:%s\n", NR, $0}' "$FILE"
else
echo "Missing file: $FILE"
fi
echo
echo "=== Search for IS NULL / NULL-safe CASE patterns near stock fields ==="
rg -n "(IS NULL|COALESCE|NULLIF).*stock_quantity|stock_quantity.*(IS NULL|COALESCE|NULLIF)" script/silver/dbt_project/models/intermediate || true
rg -n "(IS NULL|COALESCE|NULLIF).*reorder_level|reorder_level.*(IS NULL|COALESCE|NULLIF)" script/silver/dbt_project/models/intermediate || trueRepository: Ritik574-coder/dbt_learning_project Length of output: 818 🏁 Script executed: #!/bin/bash
set -euo pipefail
FILE="script/silver/dbt_project/models/marts/Dimensions/dim_products.sql"
echo "=== File: $FILE (lines 1-120) ==="
if [ -f "$FILE" ]; then
awk 'NR>=1 && NR<=120 {printf "%d:%s\n", NR, $0}' "$FILE"
else
echo "Missing file: $FILE"
fiRepository: Ritik574-coder/dbt_learning_project Length of output: 817 Avoid classifying NULL stock inputs as
💡 Proposed fix- CASE WHEN stock_quantity <= reorder_level THEN 'Yes' ELSE 'No' END AS low_stock_flag,
+ CASE
+ WHEN stock_quantity IS NULL OR reorder_level IS NULL THEN NULL
+ WHEN stock_quantity <= reorder_level THEN 'Yes'
+ ELSE 'No'
+ END AS low_stock_flag,📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
| supplier_name, | ||||||||||||||
| supplier_country, | ||||||||||||||
| warranty_years, | ||||||||||||||
| rating_avg, | ||||||||||||||
| review_count, | ||||||||||||||
| CASE | ||||||||||||||
| WHEN rating_avg >= 4.5 THEN 'Excellent' | ||||||||||||||
| WHEN rating_avg >= 3.5 THEN 'Good' | ||||||||||||||
| WHEN rating_avg >= 2.5 THEN 'Average' | ||||||||||||||
| WHEN rating_avg >= 1.0 THEN 'Poor' | ||||||||||||||
| ELSE 'Not Rated' | ||||||||||||||
| END AS rating_category, | ||||||||||||||
| launched_date, | ||||||||||||||
| product_url, | ||||||||||||||
| GETDATE() AS _loaded_at | ||||||||||||||
| FROM staging | ||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| -- Intermediate Model: int_returns_summary | ||
|
|
||
| WITH staging AS ( | ||
| SELECT * FROM {{ ref('src_returns') }} | ||
| ) | ||
|
|
||
| SELECT | ||
| return_id, | ||
| original_txn_id, | ||
| original_order_id, | ||
| customer_id, | ||
| customer_name, | ||
| product_id, | ||
| product_name, | ||
| quantity_returned, | ||
| return_date, | ||
| return_reason, | ||
| refund_amount, | ||
| refund_method, | ||
| return_channel, | ||
| restocked, | ||
| return_status, | ||
| handled_by_emp_id, | ||
| notes, | ||
| DATEPART(YEAR, return_date) AS return_year, | ||
| DATEPART(MONTH, return_date) AS return_month, | ||
| GETDATE() AS _loaded_at | ||
| FROM staging |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| -- Intermediate Model: int_reviews_summary | ||
|
|
||
| WITH staging AS ( | ||
| SELECT * FROM {{ ref('src_reviews') }} | ||
| ) | ||
|
|
||
| SELECT | ||
| review_id, | ||
| txn_id, | ||
| customer_id, | ||
| customer_name, | ||
| product_id, | ||
| product_name, | ||
| rating, | ||
| rating_text, | ||
| review_date, | ||
| verified_purchase, | ||
| helpful_votes, | ||
| review_channel, | ||
| review_title, | ||
| DATEPART(YEAR, review_date) AS review_year, | ||
| DATEPART(MONTH, review_date) AS review_month, | ||
| GETDATE() AS _loaded_at | ||
| FROM staging |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,32 @@ | ||||||||||||||
| -- Intermediate Model: int_stores_standardized | ||||||||||||||
|
|
||||||||||||||
| WITH staging AS ( | ||||||||||||||
| SELECT * FROM {{ ref('src_stores') }} | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| SELECT | ||||||||||||||
| store_id, | ||||||||||||||
| store_name, | ||||||||||||||
| store_type, | ||||||||||||||
| address, | ||||||||||||||
| city, | ||||||||||||||
| state, | ||||||||||||||
| state_full, | ||||||||||||||
| CONCAT(city, ', ', state) AS store_location, | ||||||||||||||
| zip_code, | ||||||||||||||
| country, | ||||||||||||||
| region, | ||||||||||||||
| district, | ||||||||||||||
| phone, | ||||||||||||||
| manager_name, | ||||||||||||||
| opened_date, | ||||||||||||||
| DATEDIFF(YEAR, opened_date, GETDATE()) AS years_operating, | ||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Locate and print the relevant section of the file
FILE="script/silver/dbt_project/models/intermediate/Stores/int_stores_standardized.sql"
echo "== File: $FILE =="
python3 - <<'PY'
import itertools,sys,os
path="script/silver/dbt_project/models/intermediate/Stores/int_stores_standardized.sql"
with open(path,'r',encoding='utf-8') as f:
lines=f.readlines()
for i in range(15,35):
if i<=len(lines):
print(f"{i:4d}: {lines[i-1].rstrip()}")
PY
# Search for years_operating and similar DATEDIFF usage nearby/elsewhere
echo
echo "== rg: years_operating =="
rg -n "years_operating" script/silver/dbt_project/models || true
echo
echo "== rg: DATEDIFF\(YEAR, opened_date =="
rg -n "DATEDIFF\s*\(\s*YEAR\s*,\s*opened_date" script/silver/dbt_project/models || true
echo
echo "== rg: DATEDIFF\(YEAR, .* GETDATE\(\) =="
rg -n "DATEDIFF\s*\(\s*YEAR\s*,[^)]*GETDATE\(\)\s*\)" script/silver/dbt_project/models || true
# Look for employee tenure logic if it exists (same alleged bug pattern)
echo
echo "== rg: tenure / employment years =="
rg -n "(tenure|employee.*tenure|years.*tenure|employment.*years)" script/silver/dbt_project/models || trueRepository: Ritik574-coder/dbt_learning_project Length of output: 2107 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Print more context around opened_date usage and the rest of the model
FILE="script/silver/dbt_project/models/intermediate/Stores/int_stores_standardized.sql"
echo "== Context around opened_date in $FILE =="
python3 - <<'PY'
path="script/silver/dbt_project/models/intermediate/Stores/int_stores_standardized.sql"
with open(path,'r',encoding='utf-8') as f:
lines=f.readlines()
for i,line in enumerate(lines, start=1):
if 'opened_date' in line:
start=max(1,i-5)
end=min(len(lines),i+5)
print(f"\n--- {path}:{start}-{end} (around line {i}) ---")
for j in range(start,end+1):
print(f"{j:4d}: {lines[j-1].rstrip()}")
PY
# Inspect employee tenure model for parallel pattern
EFILE="script/silver/dbt_project/models/intermediate/Employees/int_employees_standardized.sql"
echo
echo "== Context around hire_date / calculated_tenure_years in $EFILE =="
python3 - <<'PY'
path="script/silver/dbt_project/models/intermediate/Employees/int_employees_standardized.sql"
with open(path,'r',encoding='utf-8') as f:
lines=f.readlines()
for i,line in enumerate(lines, start=1):
if 'hire_date' in line or 'calculated_tenure_years' in line:
start=max(1,i-5)
end=min(len(lines),i+8)
print(f"\n--- {path}:{start}-{end} (around line {i}) ---")
for j in range(start,end+1):
print(f"{j:4d}: {lines[j-1].rstrip()}")
PY
# Search for casts/conversions of opened_date anywhere else in Stores intermediate/marts
echo
echo "== rg 'opened_date' across Stores intermediate/marts =="
rg -n "opened_date" script/silver/dbt_project/models || true
# Search for TRY_CAST/CAST patterns on opened_date specifically
echo
echo "== rg cast/opened_date patterns =="
rg -n "(CAST|TRY_CAST|CONVERT)\s*\(\s*opened_date" script/silver/dbt_project/models || trueRepository: Ritik574-coder/dbt_learning_project Length of output: 4526 Compute completed operating years (avoid anniversary overcount)
💡 Proposed fix- DATEDIFF(YEAR, opened_date, GETDATE()) AS years_operating,
+ DATEDIFF(YEAR, opened_date, CAST(GETDATE() AS DATE))
+ - CASE
+ WHEN DATEADD(YEAR, DATEDIFF(YEAR, opened_date, CAST(GETDATE() AS DATE)), opened_date) > CAST(GETDATE() AS DATE)
+ THEN 1 ELSE 0
+ END AS years_operating,📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
| sq_footage, | ||||||||||||||
| num_employees, | ||||||||||||||
| annual_rent_usd, | ||||||||||||||
| CASE WHEN sq_footage > 0 THEN TRY_CAST(num_employees AS DECIMAL(10,2)) / sq_footage * 1000 ELSE NULL END AS employees_per_1000_sqft, | ||||||||||||||
| is_active, | ||||||||||||||
| has_parking, | ||||||||||||||
| has_cafe, | ||||||||||||||
| GETDATE() AS _loaded_at | ||||||||||||||
| FROM staging | ||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| -- Intermediate Model: int_transactions_enriched | ||
|
|
||
| WITH staging AS ( | ||
|
|
||
| SELECT * | ||
| FROM {{ ref('src_transactions') }} | ||
|
|
||
| ) | ||
|
|
||
| SELECT | ||
|
|
||
| transaction_id, | ||
| order_id, | ||
| order_line_number, | ||
|
|
||
| order_date, | ||
| order_year, | ||
| order_month, | ||
| order_month_name, | ||
| order_quarter, | ||
| order_day_of_week, | ||
|
|
||
| customer_id, | ||
| product_id, | ||
|
|
||
| -- Sales Metrics | ||
| TRY_CAST(quantity_ordered AS INT) AS quantity_ordered, | ||
|
|
||
| TRY_CAST(unit_list_price AS DECIMAL(18,2)) AS unit_list_price, | ||
|
|
||
| TRY_CAST(discount_pct AS DECIMAL(18,2)) AS discount_pct, | ||
|
|
||
| TRY_CAST(unit_selling_price AS DECIMAL(18,2)) AS unit_selling_price, | ||
|
|
||
| TRY_CAST(line_total_before_tax AS DECIMAL(18,2)) AS line_total_before_tax, | ||
|
|
||
| TRY_CAST(tax_rate_pct AS DECIMAL(18,2)) AS tax_rate_pct, | ||
|
|
||
| TRY_CAST(tax_amount AS DECIMAL(18,2)) AS tax_amount, | ||
|
|
||
| TRY_CAST(line_total_with_tax AS DECIMAL(18,2)) AS line_total_with_tax, | ||
|
|
||
| -- Derived Metrics | ||
| ( | ||
| TRY_CAST(unit_selling_price AS DECIMAL(18,2)) | ||
| * | ||
| TRY_CAST(quantity_ordered AS INT) | ||
| ) AS gross_sales_amount, | ||
|
|
||
| TRY_CAST(cost_price AS DECIMAL(18,2)) AS cost_price, | ||
|
|
||
| TRY_CAST(gross_profit AS DECIMAL(18,2)) AS gross_profit, | ||
|
|
||
| ( | ||
| TRY_CAST(line_total_with_tax AS DECIMAL(18,2)) | ||
| - | ||
| TRY_CAST(cost_price AS DECIMAL(18,2)) | ||
| ) AS net_profit, | ||
|
|
||
| CASE | ||
| WHEN TRY_CAST(line_total_with_tax AS DECIMAL(18,2)) = 0 THEN NULL | ||
|
|
||
| ELSE ROUND( | ||
| ( | ||
| ( | ||
| TRY_CAST(line_total_with_tax AS DECIMAL(18,2)) | ||
| - | ||
| TRY_CAST(cost_price AS DECIMAL(18,2)) | ||
| ) | ||
| / | ||
| TRY_CAST(line_total_with_tax AS DECIMAL(18,2)) | ||
| ) * 100, | ||
| 2 | ||
| ) | ||
|
|
||
| END AS profit_margin_pct, | ||
|
|
||
| -- Dimensions | ||
| store_id, | ||
| employee_id, | ||
|
|
||
| promo_id, | ||
| promo_name, | ||
|
|
||
| LOWER(TRIM(sales_channel)) AS sales_channel, | ||
|
|
||
| payment_method, | ||
| shipping_method, | ||
| order_status, | ||
| is_returned, | ||
|
|
||
| -- Audit Column | ||
| GETDATE() AS _loaded_at | ||
|
|
||
| FROM staging |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These configuration keys use lowercase path segments (
dimensions/facts/reporting), but the actual model folders aremodels/marts/Dimensions,models/marts/Facts, andmodels/marts/Reporting; dbt treats unmatched paths as unused config, so the intended materialization/schema settings for marts will not be applied to those models.Useful? React with 👍 / 👎.