diff --git a/.gitignore b/.gitignore index f2a1d254..876fbf5f 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ profiles.yml .ruff_cache __pycache__ +dbt_internal_packages/ diff --git a/README.md b/README.md index 87fb3114..ccb147d8 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,9 @@ This is a sandbox project for exploring the basic functionality and latest featu This README will guide you through setting up the project on dbt Cloud. Working through this example should give you a good sense of how dbt Cloud works and what's involved with setting up your own project. We'll also _optionally_ cover some intermediate topics like setting up Environments and Jobs in dbt Cloud, working with a larger dataset, and setting up pre-commit hooks if you'd like. +> [!NOTE] +> **The `main` is compatible with [dbt Fusion](https://docs.getdbt.com/docs/fusion/about-fusion).** and dbt Core v1.12 and higher. It uses the latest Semantic Layer YAML spec, with semantic models embedded in model YAML files, `type: simple` metrics replacing measures, and `type_params` promoted to top-level keys. If you're looking for the legacy project using the pre-Fusion YAML spec, check out the [`jaffle-shop-old`](../../tree/jaffle-shop-old) branch. + > [!NOTE] > This project is geared towards folks learning dbt Cloud with a cloud warehouse. If you're brand new to dbt, we recommend starting with the [dbt Learn](https://learn.getdbt.com/) platform. It's a free, interactive way to learn dbt, and it's a great way to get started if you're new to the tool. If you just want to try dbt locally as quickly as possible without setting up a data warehouse check out [`jaffle_shop_duckdb`](https://github.com/dbt-labs/jaffle_shop_duckdb). diff --git a/dbt_project.yml b/dbt_project.yml index 085ef000..72ada774 100644 --- a/dbt_project.yml +++ b/dbt_project.yml @@ -36,3 +36,6 @@ models: +materialized: view marts: +materialized: table + +flags: + require_generic_test_arguments_property: true \ No newline at end of file diff --git a/models/marts/customers.yml b/models/marts/customers.yml index 1d7c9718..e880724e 100644 --- a/models/marts/customers.yml +++ b/models/marts/customers.yml @@ -1,23 +1,38 @@ models: - name: customers description: Customer overview data mart, offering key details for each unique customer. One row per customer. + semantic_model: + enabled: true + agg_time_dimension: first_ordered_at data_tests: - dbt_utils.expression_is_true: - expression: "lifetime_spend_pretax + lifetime_tax_paid = lifetime_spend" + arguments: + expression: "lifetime_spend_pretax + lifetime_tax_paid = lifetime_spend" columns: - name: customer_id description: The unique key of the orders mart. data_tests: - not_null - unique + entity: + type: primary + name: customer - name: customer_name description: Customers' full name. + dimension: + type: categorical - name: count_lifetime_orders description: Total number of orders a customer has ever placed. - name: first_ordered_at description: The timestamp when a customer placed their first order. + granularity: day + dimension: + type: time - name: last_ordered_at description: The timestamp of a customer's most recent order. + granularity: day + dimension: + type: time - name: lifetime_spend_pretax description: The sum of all the pre-tax subtotals of every order a customer has placed. - name: lifetime_tax_paid @@ -28,72 +43,47 @@ models: description: Options are 'new' or 'returning', indicating if a customer has ordered more than once or has only placed their first order to date. data_tests: - accepted_values: - values: ["new", "returning"] - -semantic_models: - - name: customers - defaults: - agg_time_dimension: first_ordered_at - description: | - Customer grain mart. - model: ref('customers') - entities: - - name: customer - expr: customer_id - type: primary - dimensions: - - name: customer_name - type: categorical - - name: customer_type - type: categorical - - name: first_ordered_at - type: time - type_params: - time_granularity: day - - name: last_ordered_at - type: time - type_params: - time_granularity: day - measures: + arguments: + values: ["new", "returning"] + dimension: + type: categorical + metrics: - name: customers description: Count of unique customers + label: Customers + type: simple agg: count_distinct expr: customer_id - name: count_lifetime_orders description: Total count of orders per customer. + label: Count Lifetime Orders + type: simple agg: sum - name: lifetime_spend_pretax - description: Customer lifetime spend before taxes. + description: Customer's lifetime spend before tax + label: LTV Pre-tax + type: simple agg: sum - name: lifetime_spend - agg: sum description: Gross customer lifetime spend inclusive of taxes. + label: Lifetime Spend + type: simple + agg: sum metrics: - - name: lifetime_spend_pretax - description: Customer's lifetime spend before tax - label: LTV Pre-tax - type: simple - type_params: - measure: lifetime_spend_pretax - - name: count_lifetime_orders - description: Count of lifetime orders - label: Count Lifetime Orders - type: simple - type_params: - measure: count_lifetime_orders - name: average_order_value description: LTV pre-tax / number of orders label: Average Order Value type: derived - type_params: - metrics: - - count_lifetime_orders - - lifetime_spend_pretax - expr: lifetime_spend_pretax / count_lifetime_orders + expr: lifetime_spend_pretax / count_lifetime_orders + input_metrics: + - name: count_lifetime_orders + - name: lifetime_spend_pretax saved_queries: - name: customer_order_metrics + description: Key customer order metrics grouped by customer. + label: Customer Order Metrics query_params: metrics: - count_lifetime_orders diff --git a/models/marts/locations.yml b/models/marts/locations.yml index 633bd679..3d519166 100644 --- a/models/marts/locations.yml +++ b/models/marts/locations.yml @@ -1,24 +1,26 @@ -semantic_models: +models: - name: locations description: | Location dimension table. The grain of the table is one row per location. - model: ref('locations') - defaults: - agg_time_dimension: opened_date - entities: - - name: location - type: primary - expr: location_id - dimensions: + semantic_model: + enabled: true + agg_time_dimension: opened_date + columns: + - name: location_id + entity: + type: primary + name: location - name: location_name - type: categorical + dimension: + type: categorical - name: opened_date - expr: opened_date - type: time - type_params: - time_granularity: day - measures: + granularity: day + dimension: + type: time + metrics: - name: average_tax_rate description: Average tax rate. - expr: tax_rate + label: Average Tax Rate + type: simple agg: average + expr: tax_rate diff --git a/models/marts/metricflow_time_spine.sql b/models/marts/metricflow_time_spine.sql index 95be185f..bd29c916 100644 --- a/models/marts/metricflow_time_spine.sql +++ b/models/marts/metricflow_time_spine.sql @@ -1,19 +1,24 @@ --- metricflow_time_spine.sql -with - -days as ( - - --for BQ adapters use "DATE('01/01/2000','mm/dd/yyyy')" - {{ dbt_date.get_base_dates(n_dateparts=365*10, datepart="day") }} +{{ + config( + materialized = 'table', + ) +}} + +with days as ( + + {{ + dbt.date_spine( + 'day', + "to_date('01/01/2000','mm/dd/yyyy')", + "to_date('01/01/2030','mm/dd/yyyy')" + ) + }} ), -cast_to_date as ( - +final as ( select cast(date_day as date) as date_day - from days - ) -select * from cast_to_date +select * from final diff --git a/models/marts/metricflow_time_spine.yml b/models/marts/metricflow_time_spine.yml new file mode 100644 index 00000000..205a3dc9 --- /dev/null +++ b/models/marts/metricflow_time_spine.yml @@ -0,0 +1,8 @@ +models: + - name: metricflow_time_spine + description: Time spine model used by MetricFlow for temporal joins and aggregations. + time_spine: + standard_granularity_column: date_day + columns: + - name: date_day + granularity: day diff --git a/models/marts/order_items.yml b/models/marts/order_items.yml index 46bc0b04..4896768d 100644 --- a/models/marts/order_items.yml +++ b/models/marts/order_items.yml @@ -1,173 +1,115 @@ models: - name: order_items + description: | + Items contained in each order. The grain of the table is one row per order item. + semantic_model: + enabled: true + agg_time_dimension: ordered_at columns: - name: order_item_id data_tests: - not_null - unique + entity: + type: primary + name: order_item - name: order_id data_tests: - relationships: - to: ref('orders') - field: order_id - -unit_tests: - - name: test_supply_costs_sum_correctly - description: "Test that the counts of drinks and food orders convert to booleans properly." - model: order_items - given: - - input: ref('stg_supplies') - rows: - - { product_id: 1, supply_cost: 4.50 } - - { product_id: 2, supply_cost: 3.50 } - - { product_id: 2, supply_cost: 5.00 } - - input: ref('stg_products') - rows: - - { product_id: 1 } - - { product_id: 2 } - - input: ref('stg_order_items') - rows: - - { order_id: 1, product_id: 1 } - - { order_id: 2, product_id: 2 } - - { order_id: 2, product_id: 2 } - - input: ref('stg_orders') - rows: - - { order_id: 1 } - - { order_id: 2 } - expect: - rows: - - { order_id: 1, product_id: 1, supply_cost: 4.50 } - - { order_id: 2, product_id: 2, supply_cost: 8.50 } - - { order_id: 2, product_id: 2, supply_cost: 8.50 } - -semantic_models: - - name: order_item - defaults: - agg_time_dimension: ordered_at - description: | - Items contatined in each order. The grain of the table is one row per order item. - model: ref('order_items') - entities: - - name: order_item - type: primary - expr: order_item_id - - name: order_id - type: foreign - expr: order_id - - name: product - type: foreign - expr: product_id - dimensions: + arguments: + to: ref('orders') + field: order_id + entity: + type: foreign + name: order_id + - name: product_id + entity: + type: foreign + name: product - name: ordered_at - expr: ordered_at - type: time - type_params: - time_granularity: day + granularity: day + dimension: + type: time - name: is_food_item - type: categorical + dimension: + type: categorical - name: is_drink_item - type: categorical - measures: + dimension: + type: categorical + metrics: - name: revenue description: The revenue generated for each order item. Revenue is calculated as a sum of revenue associated with each product in an order. + label: Revenue + type: simple agg: sum expr: product_price - name: food_revenue - description: The revenue generated for each order item. Revenue is calculated as a sum of revenue associated with each product in an order. + description: The revenue from food in each order + label: Food Revenue + type: simple agg: sum - expr: case when is_food_item then product_price else 0 end + expr: "case when is_food_item then product_price else 0 end" - name: drink_revenue - description: The revenue generated for each order item. Revenue is calculated as a sum of revenue associated with each product in an order. + description: The revenue from drinks in each order + label: Drink Revenue + type: simple agg: sum - expr: case when is_drink_item then product_price else 0 end + expr: "case when is_drink_item then product_price else 0 end" - name: median_revenue - description: The median revenue generated for each order item. + description: The median revenue generated for each order item. Excludes tax. + label: Median Revenue + type: simple agg: median expr: product_price metrics: - # Simple metrics - - name: revenue - description: Sum of the product revenue for each order item. Excludes tax. - type: simple - label: Revenue - type_params: - measure: revenue - - name: order_cost - description: Sum of cost for each order item. - label: Order Cost - type: simple - type_params: - measure: order_cost - - name: median_revenue - description: The median revenue for each order item. Excludes tax. - type: simple - label: Median Revenue - type_params: - measure: median_revenue - - name: food_revenue - description: The revenue from food in each order - label: Food Revenue - type: simple - type_params: - measure: food_revenue - - name: drink_revenue - description: The revenue from drinks in each order - label: Drink Revenue - type: simple - type_params: - measure: drink_revenue - - # Ratio Metrics + # Ratio metrics - name: food_revenue_pct description: The % of order revenue from food. label: Food Revenue % type: ratio - type_params: - numerator: food_revenue - denominator: revenue + numerator: food_revenue + denominator: revenue - name: drink_revenue_pct description: The % of order revenue from drinks. label: Drink Revenue % type: ratio - type_params: - numerator: drink_revenue - denominator: revenue + numerator: drink_revenue + denominator: revenue - # Derived Metrics + # Derived metrics - name: revenue_growth_mom - description: "Percentage growth of revenue compared to 1 month ago. Excluded tax" + description: "Percentage growth of revenue compared to 1 month ago. Excludes tax." type: derived label: Revenue Growth % M/M - type_params: - expr: (current_revenue - revenue_prev_month)*100/revenue_prev_month - metrics: - - name: revenue - alias: current_revenue - - name: revenue - offset_window: 1 month - alias: revenue_prev_month + expr: (current_revenue - revenue_prev_month)*100/revenue_prev_month + input_metrics: + - name: revenue + alias: current_revenue + - name: revenue + offset_window: 1 month + alias: revenue_prev_month - name: order_gross_profit description: Gross profit from each order. type: derived label: Order Gross Profit - type_params: - expr: revenue - cost - metrics: - - name: revenue - - name: order_cost - alias: cost + expr: revenue - cost + input_metrics: + - name: revenue + - name: order_cost + alias: cost - #Cumulative Metrics + # Cumulative metrics - name: cumulative_revenue description: The cumulative revenue for all orders. label: Cumulative Revenue (All Time) type: cumulative - type_params: - measure: revenue + input_metric: revenue saved_queries: - name: revenue_metrics + description: Key revenue metrics grouped by day. + label: Revenue Metrics query_params: metrics: - revenue @@ -179,3 +121,32 @@ saved_queries: - name: revenue_metrics config: export_as: table + +unit_tests: + - name: test_supply_costs_sum_correctly + description: "Test that the counts of drinks and food orders convert to booleans properly." + model: order_items + given: + - input: ref('stg_supplies') + rows: + - {product_id: 1, supply_cost: 4.50} + - {product_id: 2, supply_cost: 3.50} + - {product_id: 2, supply_cost: 5.00} + - input: ref('stg_products') + rows: + - {product_id: 1} + - {product_id: 2} + - input: ref('stg_order_items') + rows: + - {order_id: 1, product_id: 1} + - {order_id: 2, product_id: 2} + - {order_id: 2, product_id: 2} + - input: ref('stg_orders') + rows: + - {order_id: 1} + - {order_id: 2} + expect: + rows: + - {order_id: 1, product_id: 1, supply_cost: 4.50} + - {order_id: 2, product_id: 2, supply_cost: 8.50} + - {order_id: 2, product_id: 2, supply_cost: 8.50} diff --git a/models/marts/orders.yml b/models/marts/orders.yml index a37107c3..b6e10801 100644 --- a/models/marts/orders.yml +++ b/models/marts/orders.yml @@ -1,173 +1,121 @@ models: - name: orders description: Order overview data mart, offering key details for each order inlcluding if it's a customer's first order and a food vs. drink item breakdown. One row per order. + semantic_model: + enabled: true + agg_time_dimension: ordered_at data_tests: - dbt_utils.expression_is_true: - expression: "order_items_subtotal = subtotal" + arguments: + expression: "order_items_subtotal = subtotal" - dbt_utils.expression_is_true: - expression: "order_total = subtotal + tax_paid" + arguments: + expression: "order_total = subtotal + tax_paid" columns: - name: order_id description: The unique key of the orders mart. data_tests: - not_null - unique + entity: + type: primary + name: order_id - name: customer_id description: The foreign key relating to the customer who placed the order. data_tests: - relationships: - to: ref('stg_customers') - field: customer_id + arguments: + to: ref('stg_customers') + field: customer_id + entity: + type: foreign + name: customer + - name: location_id + entity: + type: foreign + name: location - name: order_total description: The total amount of the order in USD including tax. + dimension: + type: categorical + name: order_total_dim - name: ordered_at description: The timestamp the order was placed at. + granularity: day + dimension: + type: time - name: order_cost description: The sum of supply expenses to fulfill the order. - name: is_food_order description: A boolean indicating if this order included any food items. + dimension: + type: categorical - name: is_drink_order description: A boolean indicating if this order included any drink items. - -unit_tests: - - name: test_order_items_compute_to_bools_correctly - description: "Test that the counts of drinks and food orders convert to booleans properly." - model: orders - given: - - input: ref('order_items') - rows: - - { - order_id: 1, - order_item_id: 1, - is_drink_item: false, - is_food_item: true, - } - - { - order_id: 1, - order_item_id: 2, - is_drink_item: true, - is_food_item: false, - } - - { - order_id: 2, - order_item_id: 3, - is_drink_item: false, - is_food_item: true, - } - - input: ref('stg_orders') - rows: - - { order_id: 1 } - - { order_id: 2 } - expect: - rows: - - { - order_id: 1, - count_food_items: 1, - count_drink_items: 1, - is_drink_order: true, - is_food_order: true, - } - - { - order_id: 2, - count_food_items: 1, - count_drink_items: 0, - is_drink_order: false, - is_food_order: true, - } - -semantic_models: - - name: orders - defaults: - agg_time_dimension: ordered_at - description: | - Order fact table. This table is at the order grain with one row per order. - model: ref('orders') - entities: - - name: order_id - type: primary - - name: location - type: foreign - expr: location_id - - name: customer - type: foreign - expr: customer_id - dimensions: - - name: ordered_at - expr: ordered_at - type: time - type_params: - time_granularity: day - - name: order_total_dim - type: categorical - expr: order_total - - name: is_food_order - type: categorical - - name: is_drink_order - type: categorical + dimension: + type: categorical - name: customer_order_number - type: categorical - measures: + dimension: + type: categorical + metrics: - name: order_total - description: The total amount for each order including taxes. + description: Sum of total order amount. Includes tax + revenue. + label: Order Total + type: simple + agg: sum + - name: orders + description: Count of orders. + label: Orders + type: simple + agg: sum + expr: 1 + - name: new_customer_orders + description: New customer's first order count + label: New Customers + type: simple + agg: sum + expr: 1 + filter: | + {{ Dimension('order_id__customer_order_number') }} = 1 + - name: large_orders + description: "Count of orders with order total over 20." + label: Large Orders + type: simple + agg: sum + expr: 1 + filter: | + {{ Dimension('order_id__order_total_dim') }} >= 20 + - name: food_orders + description: Count of orders that contain food order items + label: Food Orders + type: simple agg: sum - - name: order_count expr: 1 + filter: | + {{ Dimension('order_id__is_food_order') }} = true + - name: drink_orders + description: Count of orders that contain drink order items + label: Drink Orders + type: simple agg: sum + expr: 1 + filter: | + {{ Dimension('order_id__is_drink_order') }} = true - name: tax_paid description: The total tax paid on each order. + label: Tax Paid + type: simple agg: sum - name: order_cost description: The cost for each order item. Cost is calculated as a sum of the supply cost for each order item. + label: Order Cost + type: simple agg: sum -metrics: - - name: order_total - description: Sum of total order amonunt. Includes tax + revenue. - type: simple - label: Order Total - type_params: - measure: order_total - - name: new_customer_orders - description: New customer's first order count - label: New Customers - type: simple - type_params: - measure: order_count - filter: | - {{ Dimension('order_id__customer_order_number') }} = 1 - - name: large_orders - description: "Count of orders with order total over 20." - type: simple - label: Large Orders - type_params: - measure: order_count - filter: | - {{ Dimension('order_id__order_total_dim') }} >= 20 - - name: orders - description: Count of orders. - label: Orders - type: simple - type_params: - measure: order_count - - name: food_orders - description: Count of orders that contain food order items - label: Food Orders - type: simple - type_params: - measure: order_count - filter: | - {{ Dimension('order_id__is_food_order') }} = true - - name: drink_orders - description: Count of orders that contain drink order items - label: Drink Orders - type: simple - type_params: - measure: order_count - filter: | - {{ Dimension('order_id__is_drink_order') }} = true - saved_queries: - name: order_metrics + description: Key order metrics grouped by day. + label: Order Metrics query_params: metrics: - orders @@ -181,3 +129,22 @@ saved_queries: - name: order_metrics config: export_as: table + +unit_tests: + - name: test_order_items_compute_to_bools_correctly + description: "Test that the counts of drinks and food orders convert to booleans properly." + model: orders + given: + - input: ref('order_items') + rows: + - {order_id: 1, order_item_id: 1, is_drink_item: false, is_food_item: true} + - {order_id: 1, order_item_id: 2, is_drink_item: true, is_food_item: false} + - {order_id: 2, order_item_id: 3, is_drink_item: false, is_food_item: true} + - input: ref('stg_orders') + rows: + - {order_id: 1} + - {order_id: 2} + expect: + rows: + - {order_id: 1, count_food_items: 1, count_drink_items: 1, is_drink_order: true, is_food_order: true} + - {order_id: 2, count_food_items: 1, count_drink_items: 0, is_drink_order: false, is_food_order: true} diff --git a/models/marts/products.yml b/models/marts/products.yml index 05d486b2..1a8a3c3e 100644 --- a/models/marts/products.yml +++ b/models/marts/products.yml @@ -1,26 +1,29 @@ -semantic_models: - #The name of the semantic model. +models: - name: products description: | Product dimension table. The grain of the table is one row per product. - #The name of the dbt model and schema - model: ref('products') - #Entities. These usually corespond to keys in the table. - entities: - - name: product - type: primary - expr: product_id - #Dimensions. Either categorical or time. These add additonal context to metrics. The typical querying pattern is Metric by Dimension. - dimensions: + semantic_model: + enabled: true + columns: + - name: product_id + entity: + type: primary + name: product - name: product_name - type: categorical + dimension: + type: categorical - name: product_type - type: categorical + dimension: + type: categorical - name: product_description - type: categorical + dimension: + type: categorical - name: is_food_item - type: categorical + dimension: + type: categorical - name: is_drink_item - type: categorical + dimension: + type: categorical - name: product_price - type: categorical + dimension: + type: categorical diff --git a/models/marts/supplies.yml b/models/marts/supplies.yml index 45f7b966..04fa493d 100644 --- a/models/marts/supplies.yml +++ b/models/marts/supplies.yml @@ -1,24 +1,26 @@ -semantic_models: - #The name of the semantic model. +models: - name: supplies description: | Supplies dimension table. The grain of the table is one row per supply and product combination. - #The name of the dbt model and schema - model: ref('supplies') - #Entities. These usually corespond to keys in the table. - entities: - - name: supply - type: primary - expr: supply_uuid - #Dimensions. Either categorical or time. These add additonal context to metrics. The typical querying pattern is Metric by Dimension. - dimensions: + semantic_model: + enabled: true + columns: + - name: supply_uuid + entity: + type: primary + name: supply - name: supply_id - type: categorical + dimension: + type: categorical - name: product_id - type: categorical + dimension: + type: categorical - name: supply_name - type: categorical + dimension: + type: categorical - name: supply_cost - type: categorical + dimension: + type: categorical - name: is_perishable_supply - type: categorical + dimension: + type: categorical diff --git a/models/staging/__sources.yml b/models/staging/__sources.yml index 4f9c9a8c..8ceb170e 100644 --- a/models/staging/__sources.yml +++ b/models/staging/__sources.yml @@ -9,12 +9,14 @@ sources: description: One record per person who has purchased one or more items - name: raw_orders description: One record per order (consisting of one or more order items) - loaded_at_field: ordered_at + config: + loaded_at_field: ordered_at - name: raw_items description: Items included in an order - name: raw_stores - loaded_at_field: opened_at + config: + loaded_at_field: opened_at - name: raw_products description: One record per SKU for items sold in stores - name: raw_supplies - description: One record per supply per SKU of items sold in stores + description: One record per supply per SKU of items sold in stores \ No newline at end of file diff --git a/models/staging/stg_order_items.yml b/models/staging/stg_order_items.yml index 7f8b8be9..89086233 100644 --- a/models/staging/stg_order_items.yml +++ b/models/staging/stg_order_items.yml @@ -12,5 +12,6 @@ models: data_tests: - not_null - relationships: - to: ref('stg_orders') - field: order_id + arguments: + to: ref('stg_orders') + field: order_id \ No newline at end of file diff --git a/models/staging/stg_orders.yml b/models/staging/stg_orders.yml index 907c947c..80b77aa9 100644 --- a/models/staging/stg_orders.yml +++ b/models/staging/stg_orders.yml @@ -3,10 +3,11 @@ models: description: Order data with basic cleaning and transformation applied, one row per order. data_tests: - dbt_utils.expression_is_true: - expression: "order_total - tax_paid = subtotal" + arguments: + expression: "order_total - tax_paid = subtotal" columns: - name: order_id description: The unique key for each order. data_tests: - not_null - - unique + - unique \ No newline at end of file diff --git a/package-lock.yml b/package-lock.yml index d2b9927c..c485a972 100644 --- a/package-lock.yml +++ b/package-lock.yml @@ -1,8 +1,11 @@ packages: - - package: dbt-labs/dbt_utils - version: 1.1.1 - - package: godatadriven/dbt_date - version: 0.10.0 - - git: https://github.com/dbt-labs/dbt-audit-helper.git - revision: b8f3a3348ce0ff8afc3aa4b9ade2123b00772473 -sha1_hash: f2a73967505955af30d18f70489a423fd47cdf79 +- git: https://github.com/dbt-labs/dbt-audit-helper.git + name: audit_helper + revision: 3bd0ca4e9d79b7d740ad7e77384b3d03a16cf242 +- package: godatadriven/dbt_date + name: dbt_date + version: 0.17.1 +- package: dbt-labs/dbt_utils + name: dbt_utils + version: 1.3.3 +sha1_hash: 66d060579551304b81750add4b6718298c4e1527