Skip to content

Commit 3e59360

Browse files
Ensure build_after is present in model freshness in parsing, otherwise skip freshness definition (#11711)
* Ensure `build_after` is present in model freshness in parsing, otherwise skip freshness definition * add freshness model config test * add changelog --------- Co-authored-by: Colin <[email protected]>
1 parent 87584c7 commit 3e59360

File tree

4 files changed

+100
-5
lines changed

4 files changed

+100
-5
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
kind: Fixes
2+
body: Ensure build_after is present in model freshness in parsing, otherwise skip
3+
freshness definition
4+
time: 2025-06-05T11:06:45.329942-07:00
5+
custom:
6+
Author: QMalcolm
7+
Issue: "11709"

core/dbt/contracts/graph/unparsed.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
MacroArgument,
1919
MaturityType,
2020
MeasureAggregationParameters,
21-
ModelFreshness,
2221
NodeVersion,
2322
Owner,
2423
Quoting,
@@ -226,7 +225,7 @@ class UnparsedModelUpdate(UnparsedNodeUpdate):
226225
versions: Sequence[UnparsedVersion] = field(default_factory=list)
227226
deprecation_date: Optional[datetime.datetime] = None
228227
time_spine: Optional[TimeSpine] = None
229-
freshness: Optional[ModelFreshness] = None
228+
freshness: Optional[Dict[str, Any]] = None
230229

231230
def __post_init__(self) -> None:
232231
if self.latest_version:

core/dbt/parser/schemas.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,7 @@ def parse_patch(self, block: TargetBlock[NodeTarget], refs: ParserRef) -> None:
789789
project_freshness_dict = self.project.models.get("+freshness", None)
790790
project_freshness = (
791791
ModelFreshness.from_dict(project_freshness_dict)
792-
if project_freshness_dict
792+
if project_freshness_dict and "build_after" in project_freshness_dict
793793
else None
794794
)
795795
except ValueError:
@@ -801,11 +801,18 @@ def parse_patch(self, block: TargetBlock[NodeTarget], refs: ParserRef) -> None:
801801
)
802802
project_freshness = None
803803

804-
model_freshness = block.target.freshness or None
804+
model_freshness_dict = block.target.freshness or None
805+
model_freshness = (
806+
ModelFreshness.from_dict(model_freshness_dict)
807+
if model_freshness_dict and "build_after" in model_freshness_dict
808+
else None
809+
)
805810

806811
config_freshness_dict = block.target.config.get("freshness", None)
807812
config_freshness = (
808-
ModelFreshness.from_dict(config_freshness_dict) if config_freshness_dict else None
813+
ModelFreshness.from_dict(config_freshness_dict)
814+
if config_freshness_dict and "build_after" in config_freshness_dict
815+
else None
809816
)
810817
freshness = merge_model_freshness(project_freshness, model_freshness, config_freshness)
811818

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import pytest
2+
3+
from dbt.tests.util import run_dbt
4+
5+
# Seed data for source tables
6+
seeds__source_table_csv = """id,_loaded_at
7+
1,2024-03-20 00:00:00
8+
2,2024-03-20 00:00:00
9+
3,2024-03-20 00:00:00
10+
"""
11+
12+
13+
models__no_freshness_sql = """
14+
select 1 as id
15+
"""
16+
17+
# Scenario 2: Model freshness defined with just model freshness spec
18+
models__model_freshness_schema_yml = """
19+
version: 2
20+
21+
sources:
22+
- name: my_source
23+
database: "{{ target.database }}"
24+
schema: "{{ target.schema }}"
25+
freshness:
26+
warn_after: {count: 24, period: hour}
27+
error_after: {count: 48, period: hour}
28+
loaded_at_field: _loaded_at
29+
tables:
30+
- name: source_table
31+
identifier: source_table
32+
33+
models:
34+
- name: model_a
35+
description: Model with no freshness defined
36+
- name: model_b
37+
description: Model with only model freshness defined
38+
freshness:
39+
build_after:
40+
count: 1
41+
period: day
42+
updates_on: all
43+
- name: model_c
44+
description: Model with only source freshness defined
45+
freshness:
46+
warn_after: {count: 24, period: hour}
47+
error_after: {count: 48, period: hour}
48+
loaded_at_field: _loaded_at
49+
tables:
50+
- name: source_table
51+
identifier: source_table
52+
"""
53+
54+
models__model_freshness_sql = """
55+
select 1 as id
56+
"""
57+
58+
models__source_freshness_sql = """
59+
select * from {{ source('my_source', 'source_table') }}
60+
"""
61+
62+
models__both_freshness_sql = """
63+
select * from {{ source('my_source', 'source_table') }}
64+
"""
65+
66+
67+
class TestModelFreshnessConfig:
68+
69+
@pytest.fixture(scope="class")
70+
def models(self):
71+
return {
72+
"schema.yml": models__model_freshness_schema_yml,
73+
"model_a.sql": models__no_freshness_sql,
74+
"model_b.sql": models__model_freshness_sql,
75+
"model_c.sql": models__source_freshness_sql,
76+
"model_d.sql": models__both_freshness_sql,
77+
}
78+
79+
def test_model_freshness_configs(self, project):
80+
run_dbt(["parse"])
81+
compile_results = run_dbt(["compile"])
82+
assert len(compile_results) == 4 # All 4 models compiled successfully

0 commit comments

Comments
 (0)