Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
43 changes: 43 additions & 0 deletions models/marts/dim_classes.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
with classes as (
select * from {{ ref('stg_classes') }}
),

category_hierarchy as (
select * from {{ ref('int_class_category_hierarchy') }}
),

instructors as (
select * from {{ ref('stg_instructors') }}
),

final as (
select
-- Class Details
c.class_id,
c.class_name,
c.club_location,

-- Splitting Date and Time
date(c.start_time) as class_date,
Comment thread
RJO23 marked this conversation as resolved.
format_timestamp('%H:%M', c.start_time) as start_time,
format_timestamp('%H:%M', c.end_time) as end_time,

c.duration_minutes,
c.capacity,

-- Category Hierarchy (Capitalized)
initcap(cat.category_name) as category_name,
initcap(coalesce(cat.parent_category_name, cat.category_name)) as parent_category_name,
initcap(coalesce(cat.grandparent_category_name, cat.parent_category_name, cat.category_name)) as top_level_category,

-- Instructor Details
i.instructor_first_name || ' ' || i.instructor_last_name as instructor_name

from classes c
left join category_hierarchy cat
on c.category_id = cat.category_id
left join instructors i
on c.instructor_id = i.instructor_id
)

select * from final
90 changes: 90 additions & 0 deletions models/marts/dim_classes.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
version: 2

models:
- name: dim_classes
description: "Final class dimension table containing denormalized hierarchy and instructor details."
columns:
- name: class_id
description: "Primary key for the class."
tests:
- unique
- not_null

- name: class_name
description: "Cleaned name of the fitness class."
tests:
- not_null
- accepted_values:
arguments:
values: ['Express Hiit', 'Hiit Blast', 'Boxing Basics', 'Boxing Conditioning', 'Evening Boxing', 'Flow Yoga', 'Lunch Yoga', 'Mobility Reset', 'Morning Muay Thai', 'Morning Pilates', 'Muay Thai Advanced', 'Muay Thai Fundamentals', 'Pilates Core', 'Restore Yoga', 'Stretch & Recover']

- name: instructor_name
description: "Full name of the instructor (First + Last)."
tests:
- not_null

- name: category_name
description: "The specific category of the class."
tests:
- not_null
- accepted_values:
arguments:
values: ['Fitness', 'Combat', 'Wellness', 'Strength', 'Muay Thai', 'Boxing', 'Yoga', 'Pilates', 'Hiit', 'Mobility']
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The word "values" should be indented here to make sure the structure is valid, matching the class_name section above.


- name: top_level_category
description: "The highest level grouping for the class category (e.g., Fitness, Wellness)."
tests:
- not_null
- accepted_values:
arguments:
values: ['Fitness', 'Combat', 'Wellness', 'Strength']
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"values" to be indented here too.


- name: club_location
description: "The physical gym location."
tests:
- not_null
- accepted_values:
arguments:
values: ['Bow', 'Stratford', 'Canary Wharf', 'Hackney']
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"values" to be indented.


- name: duration_minutes
description: "Calculated length of the class in minutes."
tests:
- not_null
- accepted_values:
arguments:
quote: false
values: [15, 30, 45, 60, 75, 90]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Values and quote should be indented under arguments.


unit_tests:
- name: test_dim_classes_hierarchy_coalesce
description: "Ensures the top_level_category correctly falls back up the hierarchy chain using real category names."
model: dim_classes
given:
- input: ref('stg_classes')
rows:
- {class_id: 1, class_name: 'Morning Muay Thai', category_id: 100, instructor_id: 1, capacity: 30}
- {class_id: 2, class_name: 'Pilates Core', category_id: 200, instructor_id: 1, capacity: 20}
- {class_id: 3, class_name: 'Heavy Lifting', category_id: 300, instructor_id: 1, capacity: 25}

- input: ref('stg_instructors')
rows:
- {instructor_id: 1, instructor_first_name: 'John', instructor_last_name: 'Doe'}

- input: ref('int_class_category_hierarchy')
rows:
# Case 1: Full hierarchy exists (Combat -> Boxing -> Muay Thai)
- {category_id: 100, category_name: 'Muay Thai', parent_category_name: 'Boxing', grandparent_category_name: 'Combat'}
# Case 2: No grandparent (Wellness -> Pilates)
- {category_id: 200, category_name: 'Pilates', parent_category_name: 'Wellness', grandparent_category_name: null}
# Case 3: No parent or grandparent (Standalone Strength)
- {category_id: 300, category_name: 'Strength', parent_category_name: null, grandparent_category_name: null}

expect:
rows:
# Expected 1: Grabs grandparent 'combat'
- {class_id: 1, category_name: 'Muay Thai', parent_category_name: 'Boxing', top_level_category: 'Combat'}
# Expected 2: Falls back to parent 'wellness'
- {class_id: 2, category_name: 'Pilates', parent_category_name: 'Wellness', top_level_category: 'Wellness'}
# Expected 3: Falls back to base category 'strength'
- {class_id: 3, category_name: 'Strength', parent_category_name: 'Strength', top_level_category: 'Strength'}
2 changes: 2 additions & 0 deletions models/staging/stg_classes.sql
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ staged as (

cast(category_id as integer) as category_id,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weren't we going to keep category ID as not an integer?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We did, but then it ended up clashing with a different model that someone else wrote and was throwing up an error. We decided to leave it as an integer for now.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes so in the stg_class_categgories, I believe @rosie-taylor you might have cast the parent and child ids as intergers and therfore the category id might have needed to be cast as and integer or inferred explicity.


cast(capacity as integer) as capacity,

initcap(trim(class_name)) as class_name,

trim(club_location) as club_location,
Expand Down
Loading